home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / clisp-li.000 / clisp-li / clisp-1996-07-22 / src / clos.lsp < prev    next >
Encoding:
Lisp/Scheme  |  1996-07-21  |  176.6 KB  |  4,077 lines

  1. ;;;; Common Lisp Object System fⁿr CLISP
  2. ;;;; Bruno Haible 21.8.1993
  3.  
  4. ; Zur Benutzung reicht ein einfaches (USE-PACKAGE "CLOS").
  5.  
  6.  
  7. (in-package "LISP")
  8. (export '(clos))
  9. (pushnew 'clos *features*)
  10.  
  11.  
  12. (in-package "SYSTEM") ; Trotz DEFPACKAGE n÷tig!
  13.  
  14. (defpackage "CLOS"
  15.  
  16. (:import-from "SYSTEM"
  17.   ;; Import:
  18.   sys::error-of-type                                 ; in error.d definiert
  19.   sys::function-name-p                               ; in control.d definiert
  20.   sys::block-name                                    ; in init.lsp definiert
  21. ; clos::generic-function-p                           ; in predtype.d definiert
  22. ; clos::class-p clos:class-of clos:find-class        ; in predtype.d definiert
  23. ; clos::structure-instance-p                         ; in record.d definiert
  24. ; clos::std-instance-p clos::allocate-std-instance   ; in record.d definiert
  25. ; clos::%allocate-instance                           ; in record.d definiert
  26. ; clos:slot-value clos::set-slot-value               ; in record.d definiert
  27. ; clos:slot-boundp clos:slot-makunbound              ; in record.d definiert
  28. ; clos:slot-exists-p                                 ; in record.d definiert
  29. ; clos::class-gethash clos::class-tuple-gethash      ; in hashtabl.d definiert
  30.   compiler::memq compiler::*keyword-package*         ; in compiler.lsp definiert
  31.   compiler::%generic-function-lambda                 ; in compiler.lsp definiert
  32.   compiler::%optimize-function-lambda                ; in compiler.lsp definiert
  33. ; clos:generic-flet clos:generic-labels              ; in compiler.lsp behandelt
  34.   ;; Export:
  35. ; clos::class    ; als Property in predtype.d und type.lsp, compiler.lsp benutzt
  36. ; clos:standard-generic-function ; in predtype.d, type.lsp, compiler.lsp benutzt
  37. ; clos:slot-missing clos:slot-unbound  ; von record.d aufgerufen
  38. ; clos::*make-instance-table*          ; von record.d benutzt
  39. ; clos::*reinitialize-instance-table*  ; von record.d benutzt
  40. ; clos::initial-reinitialize-instance  ; von record.d aufgerufen
  41. ; clos::initial-initialize-instance    ; von record.d aufgerufen
  42. ; clos::initial-make-instance          ; von record.d aufgerufen
  43. ; clos:print-object                    ; von io.d aufgerufen
  44. ; clos:describe-object                 ; von user2.lsp aufgerufen
  45. ; clos::define-structure-class         ; von defstruc.lsp aufgerufen
  46. ; clos::built-in-class-p               ; von type.lsp aufgerufen
  47. ; clos::subclassp                      ; von type.lsp aufgerufen, in compiler.lsp benutzt
  48. ; clos:class-name                      ; in type.lsp, compiler.lsp benutzt
  49. ; clos:find-class                      ; in compiler.lsp benutzt
  50. ; clos::defgeneric-lambdalist-callinfo ; von compiler.lsp aufgerufen
  51. ; clos::make-generic-function-form     ; von compiler.lsp aufgerufen
  52. )
  53.  
  54. ) ; defpackage
  55.  
  56. (in-package "CLOS")
  57.  
  58. ;;; Exportierungen: ** auch in init.lsp ** !
  59. (export '(
  60.   ;; Namen von Funktionen und Macros:
  61.   slot-value slot-boundp slot-makunbound slot-exists-p with-slots with-accessors
  62.   find-class class-of defclass defmethod call-next-method next-method-p
  63.   defgeneric generic-function generic-flet generic-labels
  64.   class-name
  65.   no-applicable-method no-primary-method no-next-method
  66.   find-method add-method remove-method
  67.   compute-applicable-methods method-qualifiers function-keywords
  68.   slot-missing slot-unbound
  69.   print-object describe-object
  70.   make-instance initialize-instance reinitialize-instance shared-initialize
  71.   ;; Namen von Klassen:
  72.   standard-class structure-class built-in-class
  73.   standard-object standard-generic-function standard-method
  74.   ;; andere Symbole:
  75.   standard ; Methoden-Kombination
  76. ))
  77.  
  78.  
  79. ;;; Vorbemerkungen:
  80.  
  81. ;; Abkⁿrzungen:
  82. ;; std = standard
  83. ;; gf = generic function
  84. ;; <...> = (class ...), meist = (find-class '...)
  85. ;; em = effective method
  86.  
  87.  
  88. ;;; Vordefinierte Klassen:
  89. ; Metaklassen:
  90. (defvar <class>)                       ; hier <structure-class>
  91. (defvar <standard-class>)              ; hier <structure-class>
  92. (defvar <structure-class>)             ; hier <structure-class>
  93. (defvar <built-in-class>)              ; hier <structure-class>
  94. ; Klassen:
  95. (defvar <standard-object>)             ; <standard-class>
  96. (defvar <standard-generic-function>)   ; <built-in-class>
  97. ;(defvar <standard-method>)            ; hier <structure-class>
  98. (defvar <array>)                       ; <built-in-class>
  99. (defvar <bit-vector>)                  ; <built-in-class>
  100. (defvar <character>)                   ; <built-in-class>
  101. (defvar <complex>)                     ; <built-in-class>
  102. (defvar <cons>)                        ; <built-in-class>
  103. (defvar <float>)                       ; <built-in-class>
  104. (defvar <function>)                    ; <built-in-class>
  105. (defvar <hash-table>)                  ; <built-in-class>
  106. (defvar <integer>)                     ; <built-in-class>
  107. (defvar <list>)                        ; <built-in-class>
  108. (defvar <null>)                        ; <built-in-class>
  109. (defvar <number>)                      ; <built-in-class>
  110. (defvar <package>)                     ; <built-in-class>
  111. (defvar <pathname>)                    ; <built-in-class>
  112. #+LOGICAL-PATHNAMES
  113. (defvar <logical-pathname>)            ; <built-in-class>
  114. (defvar <random-state>)                ; <built-in-class>
  115. (defvar <ratio>)                       ; <built-in-class>
  116. (defvar <rational>)                    ; <built-in-class>
  117. (defvar <readtable>)                   ; <built-in-class>
  118. (defvar <real>)                        ; <built-in-class>
  119. (defvar <sequence>)                    ; <built-in-class>
  120. (defvar <stream>)                      ; <built-in-class>
  121. (defvar <file-stream>)                 ; <built-in-class>
  122. (defvar <synonym-stream>)              ; <built-in-class>
  123. (defvar <broadcast-stream>)            ; <built-in-class>
  124. (defvar <concatenated-stream>)         ; <built-in-class>
  125. (defvar <two-way-stream>)              ; <built-in-class>
  126. (defvar <echo-stream>)                 ; <built-in-class>
  127. (defvar <string-stream>)               ; <built-in-class>
  128. (defvar <string>)                      ; <built-in-class>
  129. (defvar <symbol>)                      ; <built-in-class>
  130. (defvar <t>)                           ; <built-in-class>
  131. (defvar <vector>)                      ; <built-in-class>
  132. ; Eigene Erfindungen:
  133. (defvar <structure-object>)            ; <structure-class>
  134.  
  135.  
  136. ;;; Low-Level-ReprΣsentation:
  137.  
  138. ;; Im Runtime-System gibt es den Typ "CLOS-Instanz".
  139. ;; Erste Komponente ist die Klasse.
  140.  
  141. ;; Klassen sind Structures vom Typ CLASS,
  142. ;;   erste Komponente ist die Metaklasse, zweite Komponente der Name.
  143.  
  144. ;; Der "Wert" eines Slots, der unbound ist, ist #<UNBOUND> - was sonst?
  145.  
  146. ;; siehe RECORD.D :
  147. ; (STD-INSTANCE-P obj) testet, ob ein Objekt eine CLOS-Instanz ist.
  148. ; (ALLOCATE-STD-INSTANCE class n) liefert eine CLOS-Instanz mit Klasse class
  149. ; und n-1 zusΣtzlichen Slots.
  150. ;; siehe IO.D :
  151. ; CLOS-Instanzen werden via (PRINT-OBJECT object stream) ausgegeben.
  152.  
  153.  
  154. ;;; globale Verwaltung von Klassen und ihren Namen:
  155.  
  156. #| ; siehe PREDTYPE.D
  157. (defun find-class (symbol &optional (errorp t) environment)
  158.   (declare (ignore environment)) ; was sollte das Environment bedeuten?
  159.   (unless (symbolp symbol)
  160.     (error-of-type 'type-error
  161.       :datum symbol :expected-type 'symbol
  162.       (DEUTSCH "~S: Argument ~S ist kein Symbol."
  163.        ENGLISH "~S: argument ~S is not a symbol"
  164.        FRANCAIS "~S : L'argument ~S n'est pas un symbole.")
  165.       'find-class symbol
  166.   ) )
  167.   (let ((class (get symbol 'CLASS)))
  168.     (if (not (class-p class))
  169.       (if errorp
  170.         (error-of-type 'error
  171.           (DEUTSCH "~S: ~S benennt keine Klasse."
  172.            ENGLISH "~S: ~S does not name a class"
  173.            FRANCAIS "~S : ~S n'est pas le nom d'une classe.")
  174.           'find-class symbol
  175.         )
  176.         nil
  177.       )
  178.       class
  179. ) ) )
  180. |#
  181.  
  182. (defun (setf find-class) (new-value symbol &optional errorp environment)
  183.   (declare (ignore errorp environment)) ; was sollte das Environment bedeuten?
  184.   (unless (symbolp symbol)
  185.     (error-of-type 'type-error
  186.       :datum symbol :expected-type 'symbol
  187.       (DEUTSCH "~S: Argument ~S ist kein Symbol."
  188.        ENGLISH "~S: argument ~S is not a symbol"
  189.        FRANCAIS "~S : L'argument ~S n'est pas un symbole.")
  190.       '(setf find-class) symbol
  191.   ) )
  192.   (unless (class-p new-value)
  193.     (error-of-type 'type-error
  194.       :datum new-value :expected-type 'class
  195.       (DEUTSCH "~S: ~S ist keine Klasse."
  196.        ENGLISH "~S: ~S is not a class"
  197.        FRANCAIS "~S : ~S n'est pas une classe.")
  198.       '(setf find-class) new-value
  199.   ) )
  200.   (let ((h (get symbol 'CLASS)))
  201.     (when (class-p h)
  202.       (when (and (built-in-class-p h) (eq (class-name h) symbol)) ; auch Structure-Klassen schⁿtzen??
  203.         (error-of-type 'error
  204.           (DEUTSCH "~S: Built-In-Klasse ~S kann nicht umdefiniert werden."
  205.            ENGLISH "~S: cannot redefine built-in class ~S"
  206.            FRANCAIS "~S : La classe prΘdΘfinie ~S ne peut Ωtre redΘfinie.")
  207.           '(setf find-class) h
  208.       ) )
  209.       (when (sys::exported-lisp-symbol-p symbol)
  210.         (cerror (DEUTSCH "Die alte Definition wird weggeworfen."
  211.                  ENGLISH "The old definition will be lost"
  212.                  FRANCAIS "L'ancienne dΘfinition sera perdue.")
  213.                 (DEUTSCH "~S: Die COMMON-LISP-Klasse ~S wird umdefiniert."
  214.                  ENGLISH "~S: Redefining the COMMON LISP class ~S"
  215.                  FRANCAIS "~S : La classe ~S de COMMON-LISP va Ωtre redΘfinie.")
  216.                 '(setf find-class) symbol
  217.   ) ) ) )
  218.   (setf (get symbol 'CLASS) new-value)
  219. )
  220.  
  221. ; (CLASS-OF object) siehe PREDTYPE.D, benutzt Property CLASS.
  222.  
  223.  
  224. ;;; Slots:
  225.  
  226. #|
  227. ;; So k÷nnten die Zugriffsfunktionen aussehen, wenn man SLOT-VALUE-USING-CLASS
  228. ;; verwendet.
  229.  
  230. ; Zugriff auf Slots von Objekten der Metaklasse <standard-class>:
  231. (defun std-slot-value (instance slot-name)
  232.   (declare (compile))
  233.   (let* ((class (class-of instance))
  234.          (slot-location (gethash slot-name (class-slot-location-table class))))
  235.     ((lambda (value)
  236.        (if (eq value unbound)
  237.          (slot-unbound class instance slot-name)
  238.          value
  239.      ) )
  240.      (cond ((null slot-location)
  241.             (slot-missing class instance slot-name 'slot-value)
  242.            )
  243.            ((atom slot-location)
  244.             ; access local slot
  245.             (sys::%record-ref instance slot-location)
  246.            )
  247.            (t
  248.             ; access shared slot
  249.             (svref (class-shared-slots (car slot-location)) (cdr slot-location))
  250.            )
  251.     ))
  252. ) )
  253. (defun std-setf-slot-value (instance slot-name new-value)
  254.   (let* ((class (class-of instance))
  255.          (slot-location (gethash slot-name (class-slot-location-table class))))
  256.     (cond ((null slot-location)
  257.            (slot-missing class instance slot-name 'setf new-value)
  258.           )
  259.           ((atom slot-location)
  260.            ; access local slot
  261.            (sys::%record-store instance slot-location new-value)
  262.           )
  263.           (t
  264.            ; access shared slot
  265.            (setf (svref (class-shared-slots (car slot-location)) (cdr slot-location))
  266.                  new-value
  267.           ))
  268. ) ) )
  269. (defun std-slot-boundp (instance slot-name)
  270.   (declare (compile))
  271.   (let* ((class (class-of instance))
  272.          (slot-location (gethash slot-name (class-slot-location-table class))))
  273.     (cond ((null slot-location)
  274.            (slot-missing class instance slot-name 'slot-boundp)
  275.           )
  276.           ((atom slot-location)
  277.            ; access local slot
  278.            (not (eq (sys::%record-ref instance slot-location) unbound))
  279.           )
  280.           (t
  281.            ; access shared slot
  282.            (not (eq (svref (class-shared-slots (car slot-location)) (cdr slot-location)) unbound))
  283.           )
  284. ) ) )
  285. (defun std-slot-makunbound (instance slot-name)
  286.   (declare (compile))
  287.   (let* ((class (class-of instance))
  288.          (slot-location (gethash slot-name (class-slot-location-table class))))
  289.     (cond ((null slot-location)
  290.            (slot-missing class instance slot-name 'slot-makunbound)
  291.           )
  292.           ((atom slot-location)
  293.            ; access local slot
  294.            (sys::%record-store instance slot-location unbound)
  295.           )
  296.           (t
  297.            ; access shared slot
  298.            (setf (svref (class-shared-slots (car slot-location)) (cdr slot-location))
  299.                  unbound
  300.           ))
  301. ) ) )
  302. (defun std-slot-exists-p (instance slot-name)
  303.   (and (gethash slot-name (class-slot-location-table (class-of instance))) t)
  304. )
  305.  
  306. ;; Zugriff auf Slots allgemein:
  307. (defun slot-value (object slot-name)
  308.   (let ((class (class-of object)))
  309.     ; Metaklasse <standard-class> gesondert betrachten
  310.     ; aus Effizienzgrⁿnden und wegen Bootstrapping
  311.     (if (eq (class-of class) <standard-class>)
  312.       (std-slot-value object slot-name)
  313.       (slot-value-using-class class object slot-name)
  314. ) ) )
  315. (defun (setf slot-value) (new-value object slot-name)
  316.   (let ((class (class-of object)))
  317.     ; Metaklasse <standard-class> gesondert betrachten
  318.     ; aus Effizienzgrⁿnden und wegen Bootstrapping
  319.     (if (eq (class-of class) <standard-class>)
  320.       (std-setf-slot-value object slot-name new-value)
  321.       (setf-slot-value-using-class new-value class object slot-name)
  322. ) ) )
  323. (defun slot-boundp (object slot-name)
  324.   (let ((class (class-of object)))
  325.     ; Metaklasse <standard-class> gesondert betrachten
  326.     ; aus Effizienzgrⁿnden und wegen Bootstrapping
  327.     (if (eq (class-of class) <standard-class>)
  328.       (std-slot-boundp object slot-name)
  329.       (slot-boundp-using-class class object slot-name)
  330. ) ) )
  331. (defun slot-makunbound (object slot-name)
  332.   (let ((class (class-of object)))
  333.     ; Metaklasse <standard-class> gesondert betrachten
  334.     ; aus Effizienzgrⁿnden und wegen Bootstrapping
  335.     (if (eq (class-of class) <standard-class>)
  336.       (std-slot-makunbound object slot-name)
  337.       (slot-makunbound-using-class class object slot-name)
  338. ) ) )
  339. (defun slot-exists-p (object slot-name)
  340.   (let ((class (class-of object)))
  341.     ; Metaklasse <standard-class> gesondert betrachten
  342.     ; aus Effizienzgrⁿnden und wegen Bootstrapping
  343.     (if (eq (class-of class) <standard-class>)
  344.       (std-slot-exists-p object slot-name)
  345.       (slot-exists-p-using-class class object slot-name)
  346. ) ) )
  347.  
  348. (defun slot-value-using-class (class object slot-name)
  349.   (no-slot-error class object slot-name)
  350. )
  351. (defun setf-slot-value-using-class (new-value class object slot-name)
  352.   (declare (ignore new-value))
  353.   (no-slot-error class object slot-name)
  354. )
  355. (defun slot-boundp-using-class (class object slot-name)
  356.   (no-slot-error class object slot-name)
  357. )
  358. (defun slot-makunbound-using-class (class object slot-name)
  359.   (no-slot-error class object slot-name)
  360. )
  361. (defun slot-exists-p-using-class (class object slot-name)
  362.   (no-slot-error class object slot-name)
  363. )
  364.  
  365. (defun no-slot-error (class object slot-name)
  366.   (declare (ignore slot-name))
  367.   (error-of-type 'error
  368.     (DEUTSCH "Instanz ~S der Klasse ~S hat keine Slots (falsche Metaklasse)"
  369.      ENGLISH "instance ~S of class ~S has no slots (wrong metaclass)"
  370.      FRANCAIS "L'objet ~S appartenant α la classe ~S n'a pas de composants (mauvaise classe mΘta)")
  371.     object class
  372. ) )
  373. |#
  374.  
  375. ;; Der Effizienz halber - wir wollen den Test auf <standard-class> umgehen -
  376. ;; bekommen alle Klassen (egal ob standard- oder built-in-) eine
  377. ;; slot-location-table. Au▀erdem k÷nnen wir hier mit unbound schlecht umgehen.
  378. ;; Daher sind
  379. ;;   slot-value, set-slot-value, slot-boundp, slot-makunbound, slot-exists-p
  380. ;; nun bereits in RECORD.D enthalten.
  381.  
  382. (defsetf slot-value set-slot-value)
  383.  
  384. ;; WITH-SLOTS
  385.  
  386. (defmacro with-slots (slot-entries instance-form &body body &environment env)
  387.   (let ((vars '())
  388.         (slots '()))
  389.     (unless (listp slot-entries)
  390.       (error-of-type 'program-error
  391.         (DEUTSCH "~S: Das ist keine Liste von Slots: ~S"
  392.          ENGLISH "~S: not a list of slots: ~S"
  393.          FRANCAIS "~S : Pas une liste de composants: ~S")
  394.         'with-slots slot-entries
  395.     ) )
  396.     (dolist (slot slot-entries)
  397.       (let ((var slot))
  398.         (when (consp slot)
  399.           (unless (eql (length slot) 2)
  400.             (error-of-type 'program-error
  401.               (DEUTSCH "~S: unzulΣssige Slot/Variablen-Bezeichnung ~S"
  402.                ENGLISH "~S: invalid slot and variable specification ~S"
  403.                FRANCAIS "~S : spΘcification invalide de composant et variable: ~S")
  404.               'with-slots slot
  405.           ) )
  406.           (setq var (first slot) slot (second slot))
  407.           (unless (symbolp var)
  408.             (error-of-type 'program-error
  409.               (DEUTSCH "~S: Variable ~S sollte ein Symbol sein."
  410.                ENGLISH "~S: variable ~S should be a symbol"
  411.                FRANCAIS "~S : La variable ~S devrait Ωtre un symbole.")
  412.               'with-slots var
  413.           ) )
  414.         )
  415.         (unless (symbolp slot)
  416.           (error-of-type 'program-error
  417.             (DEUTSCH "~S: Slot-Name ~S sollte ein Symbol sein."
  418.              ENGLISH "~S: slot name ~S should be a symbol"
  419.              FRANCAIS "~S : Le nom de composant ~S devrait Ωtre un symbole.")
  420.             'with-slots slot
  421.         ) )
  422.         (push var vars)
  423.         (push slot slots)
  424.     ) )
  425.     (multiple-value-bind (body-rest declarations) (sys::parse-body body nil env)
  426.       (let ((instance-var (gensym)))
  427.         `(LET ((,instance-var ,instance-form))
  428.            (SYMBOL-MACROLET
  429.              ,(mapcar #'(lambda (var slot)
  430.                           `(,var (SLOT-VALUE ,instance-var ',slot))
  431.                         )
  432.                       (nreverse vars) (nreverse slots)
  433.               )
  434.              ,@(if declarations `((DECLARE ,@declarations)))
  435.              ,@body-rest
  436.          ) )
  437. ) ) ) )
  438.  
  439. ;; WITH-ACCESSORS
  440.  
  441. (defmacro with-accessors (slot-entries instance-form &body body &environment env)
  442.   (unless (listp slot-entries)
  443.     (error-of-type 'program-error
  444.       (DEUTSCH "~S: Das ist keine Liste von Slots: ~S"
  445.        ENGLISH "~S: not a list of slots: ~S"
  446.        FRANCAIS "~S : Pas une liste de composants: ~S")
  447.       'with-accessors slot-entries
  448.   ) )
  449.   (dolist (slot-entry slot-entries)
  450.     (unless (and (consp slot-entry) (eql (length slot-entry) 2))
  451.       (error-of-type 'program-error
  452.         (DEUTSCH "~S: unzulΣssige Slot/Accessor-Bezeichnung ~S"
  453.          ENGLISH "~S: invalid slot and accessor specification ~S"
  454.          FRANCAIS "~S : spΘcification invalide de composant et accesseur: ~S")
  455.         'with-accessors slot-entry
  456.     ) )
  457.     (unless (symbolp (first slot-entry))
  458.       (error-of-type 'program-error
  459.         (DEUTSCH "~S: Variable ~S sollte ein Symbol sein."
  460.          ENGLISH "~S: variable ~S should be a symbol"
  461.          FRANCAIS "~S : La variable ~S devrait Ωtre un symbole.")
  462.         'with-accessors (first slot-entry)
  463.     ) )
  464.     (unless (symbolp (second slot-entry))
  465.       (error-of-type 'program-error
  466.         (DEUTSCH "~S: Accessor-Name ~S sollte ein Symbol sein."
  467.          ENGLISH "~S: accessor name ~S should be a symbol"
  468.          FRANCAIS "~S : Le nom d'accesseur ~S devrait Ωtre un symbole.")
  469.         'with-accessors (second slot-entry)
  470.     ) )
  471.   )
  472.   (multiple-value-bind (body-rest declarations) (sys::parse-body body nil env)
  473.     (let ((instance-var (gensym)))
  474.       `(LET ((,instance-var ,instance-form))
  475.          (SYMBOL-MACROLET
  476.            ,(mapcar #'(lambda (slot-entry)
  477.                         `(,(first slot-entry) (,(second slot-entry) ,instance-var))
  478.                       )
  479.                     slot-entries
  480.             )
  481.            ,@(if declarations `((DECLARE ,@declarations)))
  482.            ,@body-rest
  483.        ) )
  484. ) ) )
  485.  
  486.  
  487. ;;; Klassen
  488.  
  489. ; zum Bootstrappen
  490. (eval-when (compile load eval)
  491.   (defun define-structure-class (name) (declare (ignore name)) ) ; vorlΣufig
  492. )
  493. ; alle Spuren eines frⁿher geladenen CLOS ausmerzen
  494. (eval-when (load eval)
  495.   (do-all-symbols (s) (remprop s 'CLASS))
  496. )
  497.  
  498. (defconstant empty-ht (make-hash-table :test #'eq :size 0))
  499.  
  500. (defstruct (class (:predicate nil) (:print-function print-class))
  501.   metaclass ; (class-of class) = (class-metaclass class), eine Klasse
  502.   classname ; (class-name class) = (class-classname class), ein Symbol
  503.   direct-superclasses ; Liste aller direkten Oberklassen
  504.   all-superclasses ; Hash-Tabelle aller Oberklassen (inkl. der Klasse selbst)
  505.   precedence-list ; angeordnete Liste aller Oberklassen (Klasse selbst zuerst)
  506.   (slot-location-table empty-ht) ; Hashtabelle Slotname -> wo der Slot sitzt
  507. )
  508.  
  509. (defstruct (built-in-class (:inherit class) (:conc-name "CLASS-") (:print-function print-class))
  510. )
  511. (proclaim '(notinline built-in-class-p))
  512.  
  513. (defstruct (slotted-class (:inherit class) (:predicate nil) (:copier nil) (:conc-name "CLASS-") (:print-function print-class))
  514.   slots                    ; Liste aller Slots (als Slot-Definitionen)
  515.   default-initargs         ; Default-Initargs (als Aliste Initarg -> Initer)
  516.   valid-initargs           ; Liste der gⁿltigen Initargs
  517.   instance-size            ; Anzahl der Slots der direkten Instanzen + 1
  518. )
  519.  
  520. (defstruct (structure-class (:inherit slotted-class) (:conc-name "CLASS-") (:print-function print-class))
  521.   names                    ; Codierung der include-Verschachtelung, eine Liste
  522. )
  523.  
  524. (defstruct (standard-class (:inherit slotted-class) (:conc-name "CLASS-") (:print-function print-class))
  525.   shared-slots             ; Simple-Vector mit den Werten aller Shared Slots, oder NIL
  526.   direct-slots             ; Liste der neu hinzugekommenen Slots (als Plisten)
  527.   direct-default-initargs  ; Neu hinzugekommene Default-Initargs (als Pliste)
  528. )
  529.  
  530. ; Zugriff auf Slots von Instanzen der Klasse <class> mittels der
  531. ; defstruct-Accessoren, daher hier keine Bootstrapping-Probleme.
  532.  
  533. ; Weiter Bootstrapping
  534. (%defclos
  535.   ; Erkennungszeichen fⁿr CLASS-P
  536.   (svref (get 'class 'sys::defstruct-description) 0)
  537.   ; Built-In-Klassen fⁿr CLASS-OF
  538.   (vector 'array 'bit-vector 'character 'complex 'cons 'float 'function
  539.           'hash-table 'integer 'null 'package 'pathname
  540.           #+LOGICAL-PATHNAMES 'logical-pathname
  541.           'random-state 'ratio 'readtable 'standard-generic-function
  542.           'stream 'file-stream 'synonym-stream 'broadcast-stream
  543.           'concatenated-stream 'two-way-stream 'echo-stream 'string-stream
  544.           'string 'symbol 't 'vector
  545. ) )
  546.  
  547. (defun print-class (class stream depth)
  548.   (declare (ignore depth))
  549.   (print-unreadable-object (class stream :type t)
  550.     (write (class-classname class) :stream stream)
  551. ) )
  552.  
  553.  
  554. ;;; DEFCLASS
  555.  
  556. (defmacro defclass (name superclass-specs slot-specs &rest options)
  557.   (unless (symbolp name)
  558.     (error-of-type 'program-error
  559.       (DEUTSCH "~S: Klassenname mu▀ ein Symbol sein, nicht ~S"
  560.        ENGLISH "~S: class name ~S should be a symbol"
  561.        FRANCAIS "~S : Le nom de classe ~S devrait Ωtre un symbole.")
  562.       'defclass name
  563.   ) )
  564.   (let* ((superclass-forms
  565.            (progn
  566.              (unless (listp superclass-specs)
  567.                (error-of-type 'program-error
  568.                  (DEUTSCH "~S ~S: Superklassen-Liste erwartet statt ~S"
  569.                   ENGLISH "~S ~S: expecting list of superclasses instead of ~S"
  570.                   FRANCAIS "~S ~S : on s'attend α une liste de classes supΘrieures au lieu de ~S")
  571.                  'defclass name superclass-specs
  572.              ) )
  573.              (mapcar #'(lambda (superclass)
  574.                          (unless (symbolp superclass)
  575.                            (error-of-type 'program-error
  576.                              (DEUTSCH "~S ~S: Oberklassenname mu▀ ein Symbol sein, nicht ~S"
  577.                               ENGLISH "~S ~S: superclass name ~S should be a symbol"
  578.                               FRANCAIS "~S ~S : Le nom d'une classe supΘrieure doit Ωtre un symbole et non ~S")
  579.                              'defclass name superclass
  580.                          ) )
  581.                          `(FIND-CLASS ',superclass)
  582.                        )
  583.                      superclass-specs
  584.          ) ) )
  585.          (accessor-def-forms '())
  586.          (slot-forms
  587.            (let ((slot-names '()))
  588.              (unless (listp slot-specs)
  589.                (error-of-type 'program-error
  590.                  (DEUTSCH "~S ~S: Slotspezifikationen-Liste erwartet statt ~S"
  591.                   ENGLISH "~S ~S: expecting list of slot specifications instead of ~S"
  592.                   FRANCAIS "~S ~S : on s'attend α une liste de spΘcifications de composants au lieu de ~S")
  593.                  'defclass name slot-specs
  594.              ) )
  595.              (mapcar #'(lambda (slot-spec)
  596.                          (let ((slot-name slot-spec) (slot-options '()))
  597.                            (when (consp slot-spec)
  598.                              (setq slot-name (car slot-spec) slot-options (cdr slot-spec))
  599.                            )
  600.                            (unless (symbolp slot-name)
  601.                              (error-of-type 'program-error
  602.                                (DEUTSCH "~S ~S: Slotname mu▀ ein Symbol sein, nicht ~S"
  603.                                 ENGLISH "~S ~S: slot name ~S should be a symbol"
  604.                                 FRANCAIS "~S ~S : Le nom de composant ~S doit Ωtre un symbole et non ~S")
  605.                                'defclass name slot-name
  606.                            ) )
  607.                            (if (member slot-name slot-names :test #'eq)
  608.                              (error-of-type 'program-error
  609.                                (DEUTSCH "~S ~S: Es kann nicht mehrere direkte Slots mit demselben Namen ~S geben."
  610.                                 ENGLISH "~S ~S: There may be only one direct slot with the name ~S."
  611.                                 FRANCAIS "~S ~S : Il ne peut pas y avoir plusieurs composants directs avec le mΩme nom ~S.")
  612.                                'defclass name slot-name
  613.                              )
  614.                              (push slot-name slot-names)
  615.                            )
  616.                            (let ((accessors '())
  617.                                  (readers '())
  618.                                  (writers '())
  619.                                  (allocation '())
  620.                                  (initargs '())
  621.                                  (initform nil) (initer nil)
  622.                                  (types '())
  623.                                  (documentation nil))
  624.                              (when (oddp (length slot-options))
  625.                                (error-of-type 'program-error
  626.                                  (DEUTSCH "~S ~S: Slot-Optionen zu Slot ~S sind nicht paarig."
  627.                                   ENGLISH "~S ~S: slot options for slot ~S don't come in pairs"
  628.                                   FRANCAIS "~S ~S : Les options pour le composant ~S ne viennent pas deux α deux.")
  629.                                  'defclass name slot-name
  630.                              ) )
  631.                              (do ((optionsr slot-options (cddr optionsr)))
  632.                                  ((atom optionsr))
  633.                                (let ((optionkey (first optionsr))
  634.                                      (argument (second optionsr)))
  635.                                  (case optionkey
  636.                                    ((:READER :WRITER)
  637.                                     (unless (function-name-p argument)
  638.                                       (error-of-type 'program-error
  639.                                         (DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist kein Funktionsname."
  640.                                          ENGLISH "~S ~S, slot option for slot ~S: ~S is not a function name"
  641.                                          FRANCAIS "~S ~S, option pour composant ~S : ~S n'est pas le nom d'une fonction.")
  642.                                         'defclass name slot-name argument
  643.                                     ) )
  644.                                     (case optionkey
  645.                                       (:READER (push argument readers))
  646.                                       (:WRITER (push argument writers))
  647.                                    ))
  648.                                    (:ACCESSOR
  649.                                     (unless (symbolp argument)
  650.                                       (error-of-type 'program-error
  651.                                         (DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist kein Symbol."
  652.                                          ENGLISH "~S ~S, slot option for slot ~S: ~S is not a symbol"
  653.                                          FRANCAIS "~S ~S, option pour composant ~S : ~S n'est pas un symbole.")
  654.                                         'defclass name slot-name argument
  655.                                     ) )
  656.                                     (push argument accessors)
  657.                                     (push argument readers)
  658.                                     (push `(SETF ,argument) writers)
  659.                                    )
  660.                                    (:ALLOCATION
  661.                                     (when allocation
  662.                                       (error-of-type 'program-error
  663.                                         (DEUTSCH "~S ~S, Slot-Option ~S zu Slot ~S darf nur einmal angegeben werden."
  664.                                          ENGLISH "~S ~S, slot option ~S for slot ~S may only be given once"
  665.                                          FRANCAIS "~S ~S, l'option ~S pour le composant ~S ne peut Ωtre spΘcifiΘe qu'une seule fois.")
  666.                                         'defclass name ':allocation slot-name
  667.                                     ) )
  668.                                     (case argument
  669.                                       ((:INSTANCE :CLASS) (setq allocation argument))
  670.                                       (t (error-of-type 'program-error
  671.                                            (DEUTSCH "~S ~S, Slot-Option zu Slot ~S mu▀ den Wert ~S oder ~S haben, nicht ~S"
  672.                                             ENGLISH "~S ~S, slot option for slot ~S must have the value ~S or ~S, not ~S"
  673.                                             FRANCAIS "~S ~S, l'option ~S pour le composant ~S doit avoir la valeur ~S ou ~S et non ~S")
  674.                                            'defclass name slot-name ':instance ':class argument
  675.                                    )) )  )
  676.                                    (:INITARG
  677.                                     (unless (symbolp argument)
  678.                                       (error-of-type 'program-error
  679.                                         (DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist kein Symbol."
  680.                                          ENGLISH "~S ~S, slot option for slot ~S: ~S is not a symbol"
  681.                                          FRANCAIS "~S ~S, option pour composant ~S : ~S n'est pas un symbole.")
  682.                                         'defclass name slot-name argument
  683.                                     ) )
  684.                                     (push argument initargs)
  685.                                    )
  686.                                    (:INITFORM
  687.                                     (when initform
  688.                                       (error-of-type 'program-error
  689.                                         (DEUTSCH "~S ~S, Slot-Option ~S zu Slot ~S darf nur einmal angegeben werden."
  690.                                          ENGLISH "~S ~S, slot option ~S for slot ~S may only be given once"
  691.                                          FRANCAIS "~S ~S, l'option ~S pour le composant ~S ne peut Ωtre spΘcifiΘe qu'une seule fois.")
  692.                                         'defclass name ':initform slot-name
  693.                                     ) )
  694.                                     (setq initform `(QUOTE ,argument)
  695.                                           initer (make-initer argument)
  696.                                    ))
  697.                                    (:TYPE
  698.                                     (when types
  699.                                       (error-of-type 'program-error
  700.                                         (DEUTSCH "~S ~S, Slot-Option ~S zu Slot ~S darf nur einmal angegeben werden."
  701.                                          ENGLISH "~S ~S, slot option ~S for slot ~S may only be given once"
  702.                                          FRANCAIS "~S ~S, l'option ~S pour le composant ~S ne peut Ωtre spΘcifiΘe qu'une seule fois.")
  703.                                         'defclass name ':type slot-name
  704.                                     ) )
  705.                                     (setq types (list argument))
  706.                                    )
  707.                                    (:DOCUMENTATION
  708.                                     (when documentation
  709.                                       (error-of-type 'program-error
  710.                                         (DEUTSCH "~S ~S, Slot-Option ~S zu Slot ~S darf nur einmal angegeben werden."
  711.                                          ENGLISH "~S ~S, slot option ~S for slot ~S may only be given once"
  712.                                          FRANCAIS "~S ~S, l'option ~S pour le composant ~S ne peut Ωtre spΘcifiΘe qu'une seule fois.")
  713.                                         'defclass name ':documentation slot-name
  714.                                     ) )
  715.                                     (unless (stringp argument)
  716.                                       (error-of-type 'program-error
  717.                                         (DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist kein String."
  718.                                          ENGLISH "~S ~S, slot option for slot ~S: ~S is not a string"
  719.                                          FRANCAIS "~S ~S, option pour composant ~S : ~S n'est pas une chaεne.")
  720.                                         'defclass name slot-name argument
  721.                                     ) )
  722.                                     (setq documentation argument)
  723.                                    )
  724.                                    (t
  725.                                      (error-of-type 'program-error
  726.                                        (DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist keine gⁿltige Slot-Option."
  727.                                         ENGLISH "~S ~S, slot option for slot ~S: ~S is not a valid slot option"
  728.                                         FRANCAIS "~S ~S, option pour composant ~S : ~S n'est pas une option valable.")
  729.                                        'defclass name slot-name optionkey
  730.                                    ) )
  731.                              ) ) )
  732.                              (setq readers (nreverse readers))
  733.                              (setq writers (nreverse writers))
  734.                              (dolist (funname readers)
  735.                                (push `(DEFMETHOD ,funname ((OBJECT ,name))
  736.                                         (SLOT-VALUE OBJECT ',slot-name)
  737.                                       )
  738.                                      accessor-def-forms
  739.                              ) )
  740.                              (dolist (funname writers)
  741.                                (push `(DEFMETHOD ,funname (NEW-VALUE (OBJECT ,name))
  742.                                         (SETF (SLOT-VALUE OBJECT ',slot-name) NEW-VALUE)
  743.                                       )
  744.                                      accessor-def-forms
  745.                              ) )
  746.                              `(LIST
  747.                                 :NAME ',slot-name
  748.                                 ,@(when accessors `(:ACCESSORS ',(nreverse accessors)))
  749.                                 ,@(when readers `(:READERS ',readers))
  750.                                 ,@(when writers `(:WRITERS ',writers))
  751.                                 ,@(when (eq allocation ':class) `(:ALLOCATION :CLASS))
  752.                                 ,@(when initargs `(:INITARGS ',(nreverse initargs)))
  753.                                 ,@(when initform `(#| :INITFORM ,initform |# :INITER ,initer))
  754.                                 ,@(when types `(:TYPE ',(first types)))
  755.                                 ,@(when documentation `(:DOCUMENTATION ',documentation))
  756.                               )
  757.                        ) ) )
  758.                      slot-specs
  759.         )) ) )
  760.     `(LET ()
  761.        (EVAL-WHEN (COMPILE LOAD EVAL)
  762.          (ENSURE-CLASS
  763.            ',name
  764.            :DIRECT-SUPERCLASSES (LIST ,@superclass-forms)
  765.            :DIRECT-SLOTS (LIST ,@slot-forms)
  766.            ,@(let ((metaclass nil)
  767.                    (direct-default-initargs nil)
  768.                    (documentation nil))
  769.                (dolist (option options)
  770.                  (block nil
  771.                    (when (listp option)
  772.                      (let ((optionkey (first option)))
  773.                        (when (case optionkey
  774.                                (:METACLASS metaclass)
  775.                                (:DEFAULT-INITARGS direct-default-initargs)
  776.                                (:DOCUMENTATION documentation)
  777.                              )
  778.                          (error-of-type 'program-error
  779.                            (DEUTSCH "~S ~S, Option ~S darf nur einmal angegeben werden."
  780.                             ENGLISH "~S ~S, option ~S may only be given once"
  781.                             FRANCAIS "~S ~S, l'option ~S ne peut Ωtre spΘcifiΘe qu'une seule fois.")
  782.                            'defclass name optionkey
  783.                        ) )
  784.                        (case optionkey
  785.                          (:METACLASS
  786.                           (when (eql (length option) 2)
  787.                             (let ((argument (second option)))
  788.                               (unless (symbolp argument)
  789.                                 (error-of-type 'program-error
  790.                                   (DEUTSCH "~S ~S, Option ~S: ~S ist kein Symbol."
  791.                                    ENGLISH "~S ~S, option ~S: ~S is not a symbol"
  792.                                    FRANCAIS "~S ~S, option ~S : ~S n'est pas un symbole.")
  793.                                   'defclass name option argument
  794.                               ) )
  795.                               (setq metaclass `(:METACLASS (FIND-CLASS ',argument)))
  796.                             )
  797.                             (return)
  798.                          ))
  799.                          (:DEFAULT-INITARGS
  800.                           (let ((list (rest option)))
  801.                             (when (and (consp list) (null (cdr list)) (listp (car list)))
  802.                               (setq list (car list))
  803.                               (warn (DEUTSCH "~S ~S: Option ~S sollte als ~S geschrieben werden."
  804.                                      ENGLISH "~S ~S: option ~S should be written ~S"
  805.                                      FRANCAIS "~S ~S : L'option ~S devrait Ωtre Θcrite ~S.")
  806.                                     'defclass name option (cons ':DEFAULT-INITARGS list)
  807.                             ) )
  808.                             (when (oddp (length list))
  809.                               (error-of-type 'program-error
  810.                                 (DEUTSCH "~S ~S, Option ~S: Argumente sind nicht paarig."
  811.                                  ENGLISH "~S ~S, option ~S: arguments don't come in pairs"
  812.                                  FRANCAIS "~S ~S, option ~S : Les arguments ne viennent pas deux α deux.")
  813.                                 'defclass name option
  814.                             ) )
  815.                             (setq direct-default-initargs
  816.                                   `(:DIRECT-DEFAULT-INITARGS
  817.                                     (LIST
  818.                                      ,@(let ((arglist nil) (formlist nil))
  819.                                          (do ((list list (cddr list)))
  820.                                              ((atom list))
  821.                                            (unless (symbolp (first list))
  822.                                              (error-of-type 'program-error
  823.                                                (DEUTSCH "~S ~S, Option ~S: ~S ist kein Symbol."
  824.                                                 ENGLISH "~S ~S, option ~S: ~S is not a symbol"
  825.                                                 FRANCAIS "~S ~S, option ~S : ~S n'est pas un symbole.")
  826.                                                'defclass name option (first list)
  827.                                            ) )
  828.                                            (when (member (first list) arglist)
  829.                                              (error-of-type 'program-error
  830.                                                (DEUTSCH "~S ~S, Option ~S: ~S darf nur einmal angegeben werden."
  831.                                                 ENGLISH "~S ~S, option ~S: ~S may only be given once"
  832.                                                 FRANCAIS "~S ~S, option ~S : ~S ne peut Ωtre spΘcifiΘ qu'une seule fois.")
  833.                                                'defclass name option (first list)
  834.                                            ) )
  835.                                            (push (first list) arglist)
  836.                                            (push (second list) formlist)
  837.                                          )
  838.                                          (mapcan #'(lambda (arg form)
  839.                                                      `(',arg ,(make-initer form))
  840.                                                    )
  841.                                                  (nreverse arglist) (nreverse formlist)
  842.                                        ) )
  843.                                    ))
  844.                           ) )
  845.                           (return)
  846.                          )
  847.                          (:DOCUMENTATION
  848.                           (when (eql (length option) 2)
  849.                             (let ((argument (second option)))
  850.                               (unless (stringp argument)
  851.                                 (error-of-type 'program-error
  852.                                   (DEUTSCH "~S ~S, Option ~S: ~S ist kein String."
  853.                                    ENGLISH "~S ~S, option ~S: ~S is not a string"
  854.                                    FRANCAIS "~S ~S, option ~S : ~S n'est pas une chaεne.")
  855.                                   'defclass name option argument
  856.                               ) )
  857.                               (setq documentation `(:DOCUMENTATION ',argument))
  858.                             )
  859.                             (return)
  860.                          ))
  861.                    ) ) )
  862.                    (error-of-type 'program-error
  863.                      (DEUTSCH "~S ~S: Ungⁿltige Option ~S"
  864.                       ENGLISH "~S ~S: invalid option ~S"
  865.                       FRANCAIS "~S ~S : option invalide ~S")
  866.                      'defclass name option
  867.                ) ) )
  868.                `(,@metaclass ,@direct-default-initargs ,@documentation)
  869.              )
  870.        ) )
  871.        ,@(nreverse accessor-def-forms) ; die DEFMETHODs
  872.        (FIND-CLASS ',name)
  873.      )
  874. ) )
  875. ; Ein Initer zur Laufzeit ist - um Funktionsaufrufe zu sparen -
  876. ; i.a. ein Cons (init-function . nil), bei Konstanten aber (nil . init-value).
  877. (defun make-initer (form)
  878.   (if (constantp form)
  879.     `(CONS 'NIL ,form)
  880.     `(CONS (FUNCTION (LAMBDA () ,form)) 'NIL)
  881. ) )
  882.  
  883. ; DEFCLASS-Ausfⁿhrung:
  884.  
  885. ; Zur Laufzeit noch bedeutsame Information eines Slots:
  886. (defstruct (slot-definition
  887.             (:conc-name "SLOTDEF-")
  888.             (:type vector) (:predicate nil) (:copier nil) (:constructor nil))
  889.   (name nil :type symbol)
  890.   (initargs '() :type list)
  891.   (location nil :type (or null integer cons))
  892.   (initer nil :type (or null cons))
  893. )
  894. (defstruct (standard-slot-definition (:inherit slot-definition)
  895.             (:conc-name "SLOTDEF-")
  896.             (:type vector) (:predicate nil)
  897.             (:constructor make-standard-slot-definition (name allocation initargs location initer)))
  898.   (allocation :instance :type (or (member :class :instance) class))
  899. )
  900.  
  901. (defun make-slotdef (&key name (allocation ':instance) (initargs '()) location (initer nil) (initform nil) (accessors '()) (readers '()) (writers '()) type documentation)
  902.   (declare (ignore initform accessors readers writers type documentation))
  903.   (make-standard-slot-definition name allocation initargs location initer)
  904. )
  905.  
  906. #| ; In defstruc.lsp ist im wesentlichen das Folgende enthalten.
  907. ; In record.d und hier wird benutzt, da▀ die ersten 4 Attribute ⁿbereinstimmen!
  908. (defstruct (structure-slot-definition (:include slot-definition)
  909.             (:conc-name "DS-SLOT-")
  910.             (:type vector) (:predicate nil)
  911.             (:constructor make-ds-slot (name offset location initer default type readonly)))
  912.   ;(name nil :type symbol)              ; ds-slot-name = slotdef-name !!
  913.   ;(initargs '() :type list)            ; ds-slot-initargs = slotdef-initargs !!
  914.   ;(offset nil :type (or null integer)) ; ds-slot-offset = slotdef-location !!
  915.   ;(initer nil :type (or null cons))    ; ds-slot-initer = slotdef-initer !!
  916.   (default nil)                         ; ds-slot-default
  917.   (type nil)                            ; ds-slot-type
  918.   (readonly nil)                        ; ds-slot-readonly
  919. )
  920. |#
  921.  
  922. (defun ensure-class (name &rest all-keys
  923.                           &key (metaclass <standard-class>)
  924.                                (direct-superclasses '())
  925.                                (direct-slots '())
  926.                                (direct-default-initargs '())
  927.                                (documentation nil)
  928.                           &allow-other-keys
  929.                     )
  930.   (let ((class (find-class name nil)))
  931.     (if class
  932.       ; Die einzige Modifikationen, die wir bei Klassen zulassen, sind die,
  933.       ; die bei doppeltem Laden desselben Codes auftreten k÷nnen:
  934.       ; verΣnderte Slot-Optionen :initform, :documentation,
  935.       ; verΣnderte Klassen-Optionen :default-initargs, :documentation.
  936.       (if (and (eq metaclass <standard-class>)
  937.                (eq metaclass (class-of class))
  938.                (equal direct-superclasses (class-direct-superclasses class))
  939.                (equal-slots direct-slots (class-direct-slots class))
  940.                (equal-default-initargs direct-default-initargs (class-direct-default-initargs class))
  941.           )
  942.         (progn
  943.           ; neue Slot-Inits eintragen:
  944.           (do ((l-old (class-direct-slots class) (cdr l-old))
  945.                (l-new direct-slots (cdr l-new)))
  946.               ((null l-new))
  947.             (let ((old (getf (car l-old) ':initer))
  948.                   (new (getf (car l-new) ':initer)))
  949.               (when old
  950.                 ; Slot-Initer new destruktiv in den Slot-Initer old umfⁿllen:
  951.                 (setf (car old) (car new))
  952.                 (setf (cdr old) (cdr new))
  953.           ) ) )
  954.           ; neue Default-Initargs eintragen:
  955.           (do ((l-old (class-direct-default-initargs class) (cddr l-old))
  956.                (l-new direct-default-initargs (cddr l-new)))
  957.               ((null l-new))
  958.             (let ((old (second l-old))
  959.                   (new (second l-new)))
  960.               ; Initer new destruktiv in den Initer old umfⁿllen:
  961.               (setf (car old) (car new))
  962.               (setf (cdr old) (cdr new))
  963.           ) )
  964.           ; NB: Diese Modifikationen vererben sich auch automatisch auf die
  965.           ; Unterklassen von class!
  966.           ; neue Dokumentation eintragen:
  967.           (when documentation (setf (documentation name 'TYPE) documentation))
  968.           ; modifizierte Klasse als Wert:
  969.           class
  970.         )
  971.         (error-of-type 'error
  972.           (DEUTSCH "~S: Klasse ~S kann nicht umdefiniert werden."
  973.            ENGLISH "~S: Cannot redefine class ~S"
  974.            FRANCAIS "~S : La classe ~S ne peut pas Ωtre redΘfinie.")
  975.           'defclass name
  976.       ) )
  977.       (progn
  978.         (when documentation (setf (documentation name 'TYPE) documentation))
  979.         (setf (find-class name)
  980.               (apply (cond ((eq metaclass <standard-class>) #'make-instance-standard-class)
  981.                            ((eq metaclass <built-in-class>) #'make-instance-built-in-class)
  982.                            ((eq metaclass <structure-class>) #'make-instance-structure-class)
  983.                            (t #'make-instance)
  984.                      )
  985.                      metaclass
  986.                      :name name
  987.                      all-keys
  988.       ) )     )
  989. ) ) )
  990. (defun equal-slots (slots1 slots2)
  991.   (or (and (null slots1) (null slots2))
  992.       (and (consp slots1) (consp slots2)
  993.            (equal-slot (first slots1) (first slots2))
  994.            (equal-slots (rest slots1) (rest slots2))
  995. ) )   )
  996. (defun equal-slot (slot1 slot2) ; slot1, slot2 Plisten
  997.   (or (and (null slot1) (null slot2))
  998.       (and #| (consp slot1) (consp slot2) |#
  999.            (eq (first slot1) (first slot2))
  1000.            (or (memq (first slot1) '(#| :initform |# :initer #| :documentation |# ))
  1001.                (equal (second slot1) (second slot2))
  1002.            )
  1003.            (equal-slot (cddr slot1) (cddr slot2))
  1004. ) )   )
  1005. (defun equal-default-initargs (initargs1 initargs2)
  1006.   (or (and (null initargs1) (null initargs2))
  1007.       (and (consp initargs1) (consp initargs2)
  1008.            (eq (first initargs1) (first initargs2))
  1009.            (equal-default-initargs (cddr initargs1) (cddr initargs2))
  1010. ) )   )
  1011.  
  1012. (defun add-default-superclass (direct-superclasses default-superclass)
  1013.   ; Manchmal will man eine bestimmte Oberklasse erzwingen.
  1014.   ; Sie darf aber nicht zweimal angegeben werden.
  1015.   (if (member default-superclass direct-superclasses :test #'eq)
  1016.     direct-superclasses
  1017.     (append direct-superclasses (list default-superclass))
  1018. ) )
  1019.  
  1020. ; Erzeugung einer Instanz von <standard-class>:
  1021.  
  1022. (let (unbound) (declare (compile)) ; unbound = #<unbound>
  1023. (defun def-unbound (x) (declare (compile)) (setq unbound x))
  1024. (defun make-instance-standard-class
  1025.        (metaclass &rest args
  1026.                   &key name (direct-superclasses '()) (direct-slots '())
  1027.                             (direct-default-initargs '())
  1028.                   &allow-other-keys
  1029.        )
  1030.   ; metaclass = <standard-class>
  1031.   (declare (ignore direct-superclasses direct-slots direct-default-initargs))
  1032.   (let ((class (make-standard-class :classname name :metaclass metaclass)))
  1033.     (apply #'initialize-instance-standard-class class args)
  1034. ) )
  1035. (defun initialize-instance-standard-class
  1036.            (class &key name (direct-superclasses '()) (direct-slots '())
  1037.                             (direct-default-initargs '())
  1038.                   &allow-other-keys
  1039.            )
  1040.   ; metaclass <= <standard-class>
  1041.   (unless (every #'standard-class-p direct-superclasses)
  1042.     (error-of-type 'error
  1043.       (DEUTSCH "~S ~S: Oberklasse ~S sollte zur Klasse STANDARD-CLASS geh÷ren."
  1044.        ENGLISH "~S ~S: superclass ~S should belong to class STANDARD-CLASS"
  1045.        FRANCAIS "~S ~S : La classe supΘrieure ~S n'appartient pas α la classe STANDARD-CLASS.")
  1046.       'defclass name (find-if-not #'standard-class-p direct-superclasses)
  1047.   ) )
  1048.   (setf (class-direct-superclasses class) (copy-list direct-superclasses))
  1049.   (setf (class-precedence-list class)
  1050.         (std-compute-cpl class
  1051.           (add-default-superclass direct-superclasses <standard-object>)
  1052.   )     )
  1053.   (setf (class-all-superclasses class)
  1054.         (std-compute-superclasses (class-precedence-list class))
  1055.   )
  1056.   (setf (class-direct-slots class) direct-slots)
  1057.   (setf (class-slots class) (std-compute-slots class))
  1058.   (setf (class-slot-location-table class) (make-hash-table :test #'eq))
  1059.   (setf (class-instance-size class) 1) ; Index 0 wird von der Klasse belegt
  1060.   (let ((shared-index (std-layout-slots class (class-slots class))))
  1061.     (when (plusp shared-index)
  1062.       (setf (class-shared-slots class)
  1063.             (let ((v (make-array shared-index))
  1064.                   (i 0))
  1065.               (mapc #'(lambda (slot)
  1066.                         (when (eq (slotdef-allocation slot) class)
  1067.                           (setf (svref v i)
  1068.                             (let ((init (slotdef-initer slot)))
  1069.                               (if init
  1070.                                 (if (car init) (funcall (car init)) (cdr init))
  1071.                                 unbound
  1072.                           ) ) )
  1073.                           (incf i)
  1074.                       ) )
  1075.                     (class-slots class)
  1076.               )
  1077.               v
  1078.   ) ) )     )
  1079.   (setf (class-direct-default-initargs class) direct-default-initargs)
  1080.   (setf (class-default-initargs class) ; 28.1.3.3.
  1081.         (remove-duplicates
  1082.           (mapcan
  1083.             #'(lambda (c)
  1084.                 (when (standard-class-p c)
  1085.                   (plist-to-alist (class-direct-default-initargs c))
  1086.               ) )
  1087.             (class-precedence-list class)
  1088.           )
  1089.           :key #'car
  1090.           :from-end t
  1091.   )     )
  1092.   (setf (class-valid-initargs class)
  1093.         (remove-duplicates (mapcap #'slotdef-initargs (class-slots class)))
  1094.   )
  1095.   class
  1096. )
  1097. ) ; let
  1098.  
  1099. ;; 28.1.5. Determining the Class Precedence List
  1100. ;
  1101. ; Die Menge aller Klassen bildet einen gerichteten Graphen: Klasse C sitzt
  1102. ; unterhalb der direkten Oberklassen von C. Dieser Graph ist azyklisch, weil
  1103. ; zum Zeitpunkt Definition der Klasse C alle direkten Oberklassen bereits
  1104. ; vorhanden sein mⁿssen.
  1105. ;
  1106. ; Man kann daher noethersche Induktion (Induktion von oben nach unten im
  1107. ; Klassengraphen) verwenden.
  1108. ;
  1109. ; Zu einer Klasse C sei DS(n) die Liste aller direkten Oberklassen von C.
  1110. ; Die Menge aller Oberklassen (inkl. C selbst) ist induktiv definiert als
  1111. ; S(C) := {C} union union_{D in DS(C)} S(D).
  1112. ;
  1113. ; Anders ausgedrⁿckt:
  1114. ; S(C) = { C_n : C_n in DS(C_{n-1}), ..., C_1 in DS(C_0), C_0 = C }
  1115. ;
  1116. ; Lemma 1: (a) C in S(C).
  1117. ;          (b) DS(C) subset S(C).
  1118. ;          (c) D in DS(C) ==> S(D) subset S(C).
  1119. ;          (d) D in S(C) ==> S(D) subset S(C).
  1120. ; Beweis: (a) Aus der Definition.
  1121. ;         (b) Aus (a) und der Definition.
  1122. ;         (c) Aus der Definition.
  1123. ;         (d) Aus (c) bei festem D mit Induktion ⁿber C.
  1124. ;
  1125. ; Die CPL einer Klasse C ist eine Anordnung der Menge S(C).
  1126. ; Falls CPL(C) = (... D1 ... D2 ...), schreibt man D1 < D2. Die so eingefⁿhrte
  1127. ; Relation ist eine Totalordnung auf S(C).
  1128. ; Dabei ist die folgende Menge von Restriktionen zu berⁿcksichtigen:
  1129. ; R(C) := union_{D in S(C)} DR(D)  mit
  1130. ; DR(C) := { C < C1, C1 < C2, ..., C{n-1} < C_n } falls DS(C) = (C1, ..., Cn).
  1131. ; Falls R(C) einen Zyklus enthΣlt, kann natⁿrlich R(C) nicht zu einer
  1132. ; Totalordnung vervollstΣndigt werden. Dann hei▀t R(C) inkonsistent.
  1133. ; CPL(C) wird folgenderma▀en konstruiert:
  1134. ;   L := (), R := R(C).
  1135. ;   L := (L | C), entferne alle (C < ..) aus R.
  1136. ;   Solange R /= {}, betrachte die Menge M aller minimalen Elemente von R
  1137. ;     (das sind diejenigen Klassen, die man, ohne R(C) zu verletzen, zu L
  1138. ;     hinzufⁿgen k÷nnte). Ist M leer, so hat man einen Zyklus in R(C) und
  1139. ;     bricht den Algorithmus ab. Sonst wΣhle unter den Elementen E von M
  1140. ;     dasjenige aus, das ein m÷glichst weit rechts in L gelegenes D mit
  1141. ;     E in DS(D) besitzt.
  1142. ;     L := (L | E), entferne alle (E < ..) aus R.
  1143. ;   CPL(C) := L.
  1144. ; L wird schrittweise um ein Element verlΣngert, R wird schrittweise
  1145. ; verkleinert, und R besteht immer nur aus Relationen zwischen Elementen
  1146. ; von S(C)\L.
  1147. ;
  1148. ; Lemma 2: (a) CPL(C) = (C ...).
  1149. ;          (b) Ist DS(C) = (C1, ..., Cn), so ist
  1150. ;              CPL(C) = (C ... C1 ... C2 ... ... Cn ...).
  1151. ; Beweis: (a) Klar nach Konstruktion.
  1152. ;         (b) Wenn Ci in die CPL aufgenommen wird, kann die Restriktion
  1153. ;             C{i-1} < Ci nicht mehr in R sein, also mu▀ C{i-1} schon in
  1154. ;             der CPL sein.
  1155. ;
  1156. ; Folgende Aussage ist falsch:
  1157. ; (*) Ist D in DS(C) und CPL(D) = (D1, ..., Dn), so ist
  1158. ;     CPL(C) = (C ... D1 ... D2 ... ... Dn ...).
  1159. ; Beispiel:
  1160. ;     z
  1161. ;    /|\             CPL(z) = (z)
  1162. ;   / | \            CPL(x) = (x z)
  1163. ;  x  |  x           CPL(y) = (y z)
  1164. ;  |  |  |           CPL(d) = (d x z)
  1165. ;  d  y  e           CPL(e) = (e x z)
  1166. ;   \/ \/            CPL(b) = (b d x y z)
  1167. ;   b   c            CPL(c) = (c y e x z)
  1168. ;    \ /             CPL(a) = (a b d c y e x z)
  1169. ;     a
  1170. ;                    CPL(a) enthΣlt CPL(b) nicht!
  1171. ;
  1172. #|
  1173. (defclass z () ())
  1174. (defclass x (z) ())
  1175. (defclass y (z) ())
  1176. (defclass d (x z) ())
  1177. (defclass e (x z) ())
  1178. (defclass b (d y) ())
  1179. (defclass c (y e) ())
  1180. (defclass a (b c) ())
  1181. (mapcar #'find-class '(z x y d e b c a))
  1182. |#
  1183.  
  1184. (defun std-compute-cpl (class direct-superclasses)
  1185.   (let* ((superclasses ; Liste aller Oberklassen in irgendeiner Reihenfolge
  1186.            (remove-duplicates
  1187.              (mapcap #'class-precedence-list direct-superclasses)
  1188.          ) )
  1189.          (L '())
  1190.          (R1 (list (cons class direct-superclasses)))
  1191.          (R2 (mapcar #'(lambda (D) (cons D (class-direct-superclasses D)))
  1192.                      superclasses
  1193.         ))   )
  1194.     (loop
  1195.       ; L ist die umgedrehte bisher konstruierte CPL.
  1196.       ; R1 ist die Liste der bisher relevanten Restriktionen, in der Form
  1197.       ; R1 = (... (Dj ... Dn) ...) wenn aus DR(D) = (D1 ... Dn) nur noch
  1198.       ; Dj,...,Dn ⁿbrig sind. Die Reihenfolge in R1 entspricht der in L.
  1199.       ; R2 ist die Liste der bisher irrelevanten Restriktionen.
  1200.       (when (null R1)
  1201.         (return) ; R1 = R2 = () -> fertig
  1202.       )
  1203.       (let ((M (remove-duplicates (mapcar #'first R1) :from-end t)))
  1204.         (setq M
  1205.           (remove-if
  1206.             #'(lambda (E)
  1207.                 (or (dolist (r R1 nil) (when (member E (cdr r)) (return t)))
  1208.                     (dolist (r R2 nil) (when (member E (cdr r)) (return t)))
  1209.               ) )
  1210.             M
  1211.         ) )
  1212.         (when (null M)
  1213.           (error-of-type 'error
  1214.             (DEUTSCH "~S ~S: Inkonsistenter PrΣzedenz-Graph, Zyklus ~S"
  1215.              ENGLISH "~S ~S: inconsistent precedence graph, cycle ~S"
  1216.              FRANCAIS "~S ~S : graphe de prΘcΘdences contradictoire, cycle ~S")
  1217.             'defclass (class-classname class)
  1218.             ; Zyklus finden: mit Hilfe der Restriktionen zu immer
  1219.             ; kleineren Elementen voranschreiten.
  1220.             (let* ((R0 (append R1 R2))
  1221.                    (cycle (list (car (first R0)))))
  1222.               (loop
  1223.                 (let* ((last (car cycle))
  1224.                        (next (dolist (r R0 nil)
  1225.                                (when (member last (cdr r))
  1226.                                  (return (nth (position last (cdr r)) r))
  1227.                       ))     ) )
  1228.                   (when (null next)
  1229.                     ; Offenbar ist last nun doch ein minimales Element!
  1230.                     (return '??)
  1231.                   )
  1232.                   (when (member next cycle)
  1233.                     (setf (cdr (member next cycle)) nil)
  1234.                     (return cycle)
  1235.                   )
  1236.                   (push next cycle)
  1237.             ) ) )
  1238.         ) )
  1239.         (let ((E (first M)))
  1240.           (push E L)
  1241.           (push (assoc E R2) R1)
  1242.           (setq R2 (delete E R2 :key #'first))
  1243.           (mapl #'(lambda (r) (when (eq (first (car r)) E) (pop (car r)))) R1)
  1244.           (setq R1 (delete-if #'null R1))
  1245.     ) ) )
  1246.     (setq L (nreverse L))
  1247.     ; Teste, ob L mit den CPL(D), D in direct-superclasses, vertrΣglich ist:
  1248.     (mapc #'(lambda (D)
  1249.               (unless ; Ist (class-precedence-list D) Teil-Liste von L ?
  1250.                 (do ((CL L)
  1251.                      (DL (class-precedence-list D) (cdr DL)))
  1252.                     ((null DL) t)
  1253.                   (when (null (setq CL (member (car DL) CL))) (return nil))
  1254.                 )
  1255.                 (warn (DEUTSCH "(class-precedence-list ~S) und (class-precedence-list ~S) sind nicht vertrΣglich."
  1256.                        ENGLISH "(class-precedence-list ~S) and (class-precedence-list ~S) are inconsistent"
  1257.                        FRANCAIS "(class-precedence-list ~S) et (class-precedence-list ~S) sont contradictoires.")
  1258.                       class D
  1259.             ) ) )
  1260.           direct-superclasses
  1261.     )
  1262.     L
  1263. ) )
  1264.  
  1265. ; Stopft alle Oberklassen (aus der precedence-list) in eine Hash-Tabelle.
  1266. (defun std-compute-superclasses (precedence-list)
  1267.   (let ((ht (make-hash-table :test #'eq)))
  1268.     (mapc #'(lambda (superclass) (setf (gethash superclass ht) t))
  1269.           precedence-list
  1270.     )
  1271.     ht
  1272. ) )
  1273.  
  1274. ; Hilfsfunktion (p1 v1 ... pn vn) -> ((p1 . v1) ... (pn . vn))
  1275. (defun plist-to-alist (pl &aux (al '()))
  1276.   (loop
  1277.     (when (null pl) (return))
  1278.     (setq al (acons (first pl) (second pl) al))
  1279.     (setq pl (cddr pl))
  1280.   )
  1281.   (nreverse al)
  1282. )
  1283.  
  1284. ; Hilfsfunktion ((p1 . v1) ... (pn . vn)) -> (p1 v1 ... pn vn)
  1285. (defun alist-to-plist (al)
  1286.   (mapcan #'(lambda (pv) (list (car pv) (cdr pv))) al)
  1287. )
  1288.  
  1289. ;; 28.1.3.2. Inheritance of Slots and Slot Options
  1290.  
  1291. (defun std-compute-slots (class &optional (more-direct-slots '()))
  1292.   ; Alle Slot-Specifier sammeln, geordnet nach PrΣzedenz:
  1293.   (let ((all-slots
  1294.           (mapcan
  1295.             #'(lambda (c)
  1296.                 (mapcar #'(lambda (slot)
  1297.                             (setq slot (plist-to-alist slot))
  1298.                             (when (eq (cdr (assoc ':allocation slot)) ':class)
  1299.                               (setf (cdr (assoc ':allocation slot)) c)
  1300.                             )
  1301.                             slot
  1302.                           )
  1303.                   (append
  1304.                     (if (standard-class-p c) (class-direct-slots c))
  1305.                     (if (eq c class) more-direct-slots)
  1306.               ) ) )
  1307.             (class-precedence-list class)
  1308.        )) )
  1309.     ; Aufspalten nach Slot-Namen:
  1310.     (setq all-slots
  1311.       (let ((ht (make-hash-table :test #'eq)))
  1312.         (dolist (slot all-slots)
  1313.           (assert (eq (caar slot) ':name))
  1314.           (push (cdr slot) (gethash (cdar slot) ht nil))
  1315.         )
  1316.         (let ((L nil))
  1317.           (maphash #'(lambda (name slots) (push (cons name (nreverse slots)) L)) ht)
  1318.           L ; nicht (nreverse L), da maphash die Reihenfolge umdreht
  1319.     ) ) )
  1320.     ; all-slots ist nun eine Liste von Listen der Form
  1321.     ; (name most-specific-slotspec ... least-specific-slotspec).
  1322.     (mapcar #'(lambda (slot)
  1323.                 (let ((name (car slot))
  1324.                       (slotspecs (cdr slot)))
  1325.                   (apply #'make-slotdef
  1326.                     :name name
  1327.                     (alist-to-plist
  1328.                       `(,(or (assoc ':allocation (first slotspecs))
  1329.                              `(:allocation . :instance)
  1330.                          )
  1331.                         #|
  1332.                         ,@(let ((accessors
  1333.                                   (mapcap #'(lambda (slotspec) (cdr (assoc ':accessors slotspec)))
  1334.                                           slotspecs
  1335.                                )) )
  1336.                             (if accessors `((:accessors . ,accessors)))
  1337.                           )
  1338.                         |#
  1339.                         ,@(let ((initargs
  1340.                                   (remove-duplicates
  1341.                                     (mapcap #'(lambda (slotspec) (cdr (assoc ':initargs slotspec)))
  1342.                                             slotspecs
  1343.                                     )
  1344.                                     :from-end t
  1345.                                )) )
  1346.                             (if initargs `((:initargs . ,initargs)))
  1347.                           )
  1348.                         ,@(dolist (slotspec slotspecs '())
  1349.                             (when (assoc ':initer slotspec)
  1350.                               (return `(#| ,(assoc ':initform slotspec) |# ,(assoc ':initer slotspec)))
  1351.                           ) )
  1352.                         #|
  1353.                         ,(let ((types '()))
  1354.                            (dolist (slotspec slotspecs)
  1355.                              (when (assoc ':type slotspec)
  1356.                                (push (cdr (assoc ':type slotspec)) types)
  1357.                            ) )
  1358.                            `(:type . ,(if types `(AND ,@(nreverse types)) 'T))
  1359.                          )
  1360.                         |#
  1361.                         #|
  1362.                         ,@(dolist (slotspec slotspecs '())
  1363.                             (when (assoc ':documentation slotspec)
  1364.                               (return `(,(assoc ':documentation slotspec)))
  1365.                           ) )
  1366.                         |#
  1367.                        )
  1368.               ) ) ) )
  1369.             all-slots
  1370.     )
  1371. ) )
  1372.  
  1373. ;; Allocation of local and shared slots
  1374.  
  1375. ; Add the local and shared slots to the slot-location-table ht,
  1376. ; incrementing the instance-size, and return the new shared-size.
  1377. (defun std-layout-slots (class slots)
  1378.   (let ((ht (class-slot-location-table class))
  1379.         (local-index (class-instance-size class))
  1380.         (shared-index 0))
  1381.     (mapc #'(lambda (slot)
  1382.               (let* ((name (slotdef-name slot))
  1383.                      (allocation (slotdef-allocation slot))
  1384.                      (location
  1385.                        (cond ((eq allocation ':instance) ; local slot
  1386.                               (prog1 local-index (incf local-index))
  1387.                              )
  1388.                              ((eq allocation class) ; new shared slot
  1389.                               (prog1 (cons class shared-index) (incf shared-index))
  1390.                              )
  1391.                              (t ; inherited shared slot
  1392.                               (gethash name (class-slot-location-table allocation))
  1393.                     )) )     )
  1394.                 (setf (slotdef-location slot) location)
  1395.                 (setf (gethash name ht) location)
  1396.             ) )
  1397.           slots
  1398.     )
  1399.     (setf (class-instance-size class) local-index)
  1400.     shared-index
  1401. ) )
  1402.  
  1403.  
  1404. ; Erzeugung einer Instanz von <built-in-class>:
  1405.  
  1406. (defun make-instance-built-in-class
  1407.        (metaclass &key name (direct-superclasses '())
  1408.                   &allow-other-keys
  1409.        )
  1410.   ; metaclass = <built-in-class>
  1411.   (unless (every #'built-in-class-p direct-superclasses)
  1412.     (error-of-type 'error
  1413.       (DEUTSCH "~S: Oberklasse ~S sollte zur Klasse BUILT-IN-CLASS geh÷ren."
  1414.        ENGLISH "~S: superclass ~S should belong to class BUILT-IN-CLASS"
  1415.        FRANCAIS "~S : La classe supΘrieure ~S n'appartient pas α la classe BUILT-IN-CLASS.")
  1416.       name (find-if-not #'built-in-class-p direct-superclasses)
  1417.   ) )
  1418.   (let ((class (make-built-in-class :classname name :metaclass metaclass)))
  1419.     (setf (class-direct-superclasses class) (copy-list direct-superclasses))
  1420.     (setf (class-precedence-list class)
  1421.           (std-compute-cpl class direct-superclasses)
  1422.     )
  1423.     (setf (class-all-superclasses class)
  1424.           (std-compute-superclasses (class-precedence-list class))
  1425.     )
  1426.     class
  1427. ) )
  1428.  
  1429.  
  1430. ; Erzeugung einer Instanz von <structure-class>:
  1431.  
  1432. (defun make-instance-structure-class
  1433.        (metaclass &rest args
  1434.                   &key name (direct-superclasses '())
  1435.                        ; The following keys come from ENSURE-CLASS.
  1436.                        (direct-slots '()) (direct-default-initargs '())
  1437.                        ; The following keys come from DEFINE-STRUCTURE-CLASS.
  1438.                        names (slots '()) (size 1)
  1439.                   &allow-other-keys
  1440.        )
  1441.   ; metaclass = <structure-class>
  1442.   (declare (ignore direct-superclasses direct-slots direct-default-initargs names slots size))
  1443.   (let ((class (make-structure-class :classname name :metaclass metaclass)))
  1444.     (apply #'initialize-instance-structure-class class args)
  1445. ) )
  1446. (defun initialize-instance-structure-class
  1447.            (class &key name (direct-superclasses '())
  1448.                        ; The following keys come from ENSURE-CLASS.
  1449.                        (direct-slots '()) (direct-default-initargs '())
  1450.                        ; The following keys come from DEFINE-STRUCTURE-CLASS.
  1451.                        names (slots '()) (size 1)
  1452.                   &allow-other-keys
  1453.        )
  1454.   ; metaclass <= <structure-class>
  1455.   (unless (null (cdr direct-superclasses))
  1456.     (error-of-type 'error
  1457.       (DEUTSCH "~S: Metaklasse STRUCTURE-CLASS lΣ▀t nur eine direkte Oberklasse zu."
  1458.        ENGLISH "~S: metaclass STRUCTURE-CLASS forbids more than one direct superclass"
  1459.        FRANCAIS "~S : La classe mΘta STRUCTURE-CLASS ne permet qu'une seule classe supΘrieure.")
  1460.       name
  1461.   ) )
  1462.   (unless (every #'structure-class-p direct-superclasses)
  1463.     (error-of-type 'error
  1464.       (DEUTSCH "~S: Oberklasse ~S sollte zur Klasse STRUCTURE-CLASS geh÷ren."
  1465.        ENGLISH "~S: superclass ~S should belong to class STRUCTURE-CLASS"
  1466.        FRANCAIS "~S : La classe supΘrieure ~S n'appartient pas α la classe STRUCTURE-CLASS.")
  1467.       name (first direct-superclasses)
  1468.   ) )
  1469.   (setf (class-direct-superclasses class) (copy-list direct-superclasses))
  1470.   (setf (class-precedence-list class)
  1471.         (std-compute-cpl class
  1472.           (add-default-superclass
  1473.             (add-default-superclass direct-superclasses
  1474.                                     <structure-object>)
  1475.                                     <t>)
  1476.   )     )
  1477.   (setf (class-all-superclasses class)
  1478.         (std-compute-superclasses (class-precedence-list class))
  1479.   )
  1480.   ; When called via ENSURE-CLASS, we have to do inheritance of slots.
  1481.   (unless names
  1482.     (setq names
  1483.           (cons name
  1484.                 (if direct-superclasses (class-names (first direct-superclasses)) '())
  1485.     )     )
  1486.     (when direct-superclasses
  1487.       (setq slots (class-slots (first direct-superclasses)))
  1488.       (setq size (class-instance-size (first direct-superclasses)))
  1489.   ) )
  1490.   (setf (class-slot-location-table class)
  1491.         (make-hash-table :test #'eq 
  1492.           :initial-contents
  1493.             (mapcar #'(lambda (slot)
  1494.                         (cons (slotdef-name slot) (slotdef-location slot))
  1495.                       )
  1496.                     slots
  1497.   )     )   )
  1498.   (setf (class-instance-size class) size)
  1499.   (setf (class-slots class) slots)
  1500.   ; When called via ENSURE-CLASS, we may have to treat additional direct slots.
  1501.   (when direct-slots
  1502.     (let* ((more-slots (std-compute-slots class direct-slots))
  1503.            (shared-index (std-layout-slots class more-slots)))
  1504.       (when (plusp shared-index)
  1505.         (error-of-type 'error
  1506.           (DEUTSCH "~S: Metaklasse STRUCTURE-CLASS lΣ▀t nur keine Shared Slots zu."
  1507.            ENGLISH "~S: metaclass STRUCTURE-CLASS does not support shared slots"
  1508.            FRANCAIS "~S : La classe mΘta STRUCTURE-CLASS ne supporte pas les slots partagΘs.")
  1509.           name
  1510.       ) )
  1511.       (setf (class-slots class) (append (class-slots class) more-slots))
  1512.   ) )
  1513.   (setf (class-default-initargs class)
  1514.         (remove-duplicates
  1515.           (append (plist-to-alist direct-default-initargs)
  1516.                   (mapcap
  1517.                     #'(lambda (c)
  1518.                         (when (structure-class-p c)
  1519.                           (class-default-initargs c)
  1520.                       ) )
  1521.                     (cdr (class-precedence-list class))
  1522.           )       )
  1523.           :key #'car
  1524.           :from-end t
  1525.   )     )
  1526.   (setf (class-valid-initargs class)
  1527.         (remove-duplicates (mapcap #'slotdef-initargs (class-slots class)))
  1528.   )
  1529.   (setf (class-names class) names)
  1530.   class
  1531. )
  1532.  
  1533. ; DEFSTRUCT-Hook
  1534. (defun define-structure-class (name)
  1535.   (let ((descr (get name 'sys::defstruct-description)))
  1536.     (when descr
  1537.       (let* ((names (svref descr 0))
  1538.              (all-slots (svref descr 3))
  1539.              (slots (remove-if-not #'sys::ds-slot-name all-slots)))
  1540.         (setf (find-class name)
  1541.               (make-instance-structure-class <structure-class>
  1542.                 :name name
  1543.                 :direct-superclasses
  1544.                   (if (cdr names) (list (find-class (second names))) '())
  1545.                 :names names
  1546.                 :slots slots
  1547.                 :size (if all-slots (1+ (sys::ds-slot-offset (car (last all-slots)))) 1)
  1548. ) ) ) ) )     )
  1549.  
  1550. ;; Bootstrapping
  1551. (progn
  1552.   ; 1. Klasse <t>
  1553.   (setq <t>
  1554.         (make-instance-built-in-class nil :name 't :direct-superclasses '())
  1555.   )
  1556.   ; 2. Klassen <structure-class> und <structure-object>
  1557.   (setq <structure-class> (make-structure-class)) ; Dummy, damit (setf find-class) geht
  1558.   (setq <structure-object> <t>)
  1559.   (setq <structure-object>
  1560.         (make-instance-structure-class <structure-class>
  1561.           :name 'structure-object
  1562.           :direct-superclasses '()
  1563.           :names '(structure-object)
  1564.   )     )
  1565.   (setf (find-class 'structure-object) <structure-object>)
  1566.   (setq <class> (define-structure-class 'class))
  1567.   (let ((<slotted-class> (define-structure-class 'slotted-class)))
  1568.     (setq <structure-class> (define-structure-class 'structure-class))
  1569.     (setf (class-metaclass <structure-object>) <structure-class>)
  1570.     (setf (class-metaclass <class>) <structure-class>)
  1571.     (setf (class-metaclass <slotted-class>) <structure-class>)
  1572.     (setf (class-metaclass <structure-class>) <structure-class>)
  1573.   )
  1574.   ; 3. Alle structure-Klassen
  1575.   (labels ((define-structure-class-with-includes (name)
  1576.              (when (get name 'sys::defstruct-description)
  1577.                (unless (find-class name nil)
  1578.                  (let ((names (svref (get name 'sys::defstruct-description) 0)))
  1579.                    (when (cdr names)
  1580.                      (define-structure-class-with-includes (second names))
  1581.                  ) )
  1582.                  (define-structure-class name)
  1583.           )) ) )
  1584.     (do-all-symbols (s) (define-structure-class-with-includes s))
  1585.   )
  1586.   ; 4. Klassen <standard-class>, <built-in-class>
  1587.   (setq <standard-class> (find-class 'standard-class))
  1588.   (setq <built-in-class> (find-class 'built-in-class))
  1589.   ; 5. Klasse <t> zu Ende
  1590.   (setf (class-metaclass <t>) <built-in-class>)
  1591.   (setf (find-class 't) <t>)
  1592.   ; 6. Klasse <standard-object>
  1593.   (setq <standard-object>
  1594.         (make-standard-class
  1595.           :classname 'standard-object
  1596.           :metaclass <standard-class>
  1597.           :direct-superclasses `(,<t>)
  1598.           :direct-slots '()
  1599.           :slots '()
  1600.           :slot-location-table empty-ht
  1601.           :instance-size 1
  1602.           :direct-default-initargs nil
  1603.           :default-initargs nil
  1604.   )     )
  1605.   (setf (class-all-superclasses <standard-object>)
  1606.         (std-compute-superclasses
  1607.           (setf (class-precedence-list <standard-object>)
  1608.                 `(,<standard-object> ,<t>)
  1609.   )     ) )
  1610.   (setf (find-class 'standard-object) <standard-object>)
  1611.   ; 7. Wert #<unbound>
  1612.   (def-unbound
  1613.     (sys::%record-ref (allocate-std-instance <standard-object> 2) 1)
  1614.   )
  1615. )
  1616.  
  1617.  
  1618. ;; 28.1.4. Integrating Types and Classes
  1619. (defun subclassp (class1 class2)
  1620.   (values
  1621.     (gethash class2 (class-all-superclasses class1)) ; T oder (Default) NIL
  1622. ) )
  1623.  
  1624. ;; Built-In-Klassen installieren
  1625. ; Table 28-1, CLtL2 p. 783
  1626. (macrolet ((def (&rest classes &aux (new (car (last classes))))
  1627.              (let ((name (intern (string-trim "<>" (symbol-name new)))))
  1628.                `(setf (find-class ',name)
  1629.                   (setq ,new
  1630.                     (make-instance-built-in-class <built-in-class>
  1631.                       :name ',name
  1632.                       :direct-superclasses (list ,@(cdr (reverse classes)))
  1633.                 ) ) )
  1634.           )) )
  1635.  ;(def <t>)
  1636.   (def <t> <character>)
  1637.   (def <t> <function>)
  1638.   (def     <function> <standard-generic-function>)
  1639.   (def <t> <hash-table>)
  1640.   (def <t> <package>)
  1641.   (def <t> <pathname>)
  1642.   #+LOGICAL-PATHNAMES
  1643.   (def     <pathname> <logical-pathname>)
  1644.   (def <t> <random-state>)
  1645.   (def <t> <readtable>)
  1646.   (def <t> <stream>)
  1647.   (def     <stream> <file-stream>)
  1648.   (def     <stream> <synonym-stream>)
  1649.   (def     <stream> <broadcast-stream>)
  1650.   (def     <stream> <concatenated-stream>)
  1651.   (def     <stream> <two-way-stream>)
  1652.   (def     <stream> <echo-stream>)
  1653.   (def     <stream> <string-stream>)
  1654.   (def <t> <symbol>)
  1655.   (def <t> <sequence>)
  1656.   (def     <sequence> <list>)
  1657.   (def                <list> <cons>)
  1658.   (def                <list> <symbol> <null>)
  1659.   (def <t>            <array>)
  1660.   (def     <sequence> <array> <vector>)
  1661.   (def                        <vector> <bit-vector>)
  1662.   (def                        <vector> <string>)
  1663.   (def <t> <number>)
  1664.   (def     <number> <complex>)
  1665.   (def     <number> <real>)
  1666.   (def              <real> <float>)
  1667.   (def              <real> <rational>)
  1668.   (def                     <rational> <ratio>)
  1669.   (def                     <rational> <integer>)
  1670. )
  1671.  
  1672. ; Weiter Bootstrapping
  1673. (%defclos
  1674.   ; Erkennungszeichen fⁿr CLASS-P
  1675.   (svref (get 'class 'sys::defstruct-description) 0)
  1676.   ; Built-In-Klassen fⁿr CLASS-OF
  1677.   (vector <array> <bit-vector> <character> <complex> <cons> <float> <function>
  1678.           <hash-table> <integer> <null> <package> <pathname>
  1679.           #+LOGICAL-PATHNAMES <logical-pathname>
  1680.           <random-state> <ratio> <readtable> <standard-generic-function>
  1681.           <stream> <file-stream> <synonym-stream> <broadcast-stream>
  1682.           <concatenated-stream> <two-way-stream> <echo-stream> <string-stream>
  1683.           <string> <symbol> <t> <vector>
  1684. ) )
  1685.  
  1686. ;; Schnitt zweier Built-In-Klassen:
  1687. ; Abweichungen von der Single-Inheritance sind nur
  1688. ; (AND <sequence> <array>) = <vector> und (AND <list> <symbol>) = <null>.
  1689. (defun bc-p (class)
  1690.   (or (built-in-class-p class)
  1691.       (eq class <standard-object>)
  1692.       (eq class <structure-object>)
  1693. ) )
  1694. (defun bc-and (class1 class2) ; liefert (AND class1 class2)
  1695.   (cond ((subclassp class1 class2) class1)
  1696.         ((subclassp class2 class1) class2)
  1697.         ((or (and (subclassp <sequence> class1) (subclassp <array> class2))
  1698.              (and (subclassp <sequence> class2) (subclassp <array> class1))
  1699.          )
  1700.          <vector>
  1701.         )
  1702.         ((or (and (subclassp <list> class1) (subclassp <symbol> class2))
  1703.              (and (subclassp <list> class2) (subclassp <symbol> class1))
  1704.          )
  1705.          <null>
  1706.         )
  1707.         (t nil)
  1708. ) )
  1709. (defun bc-and-not (class1 class2) ; liefert eine Klasse c mit
  1710.                                   ; (AND class1 (NOT class2)) <= c <= class1
  1711.   (cond ((subclassp class1 class2) nil)
  1712.         ((and (eq class1 <sequence>) (subclassp <vector> class2)) <list>)
  1713.         ((and (eq class1 <sequence>) (subclassp <list> class2)) <vector>)
  1714.         ((and (eq class1 <list>) (subclassp <null> class2)) <cons>)
  1715.         (t class1)
  1716. ) )
  1717.  
  1718.  
  1719. ;;; Methoden
  1720.  
  1721. (defstruct (standard-method (:conc-name "STD-METHOD-") (:print-function print-std-method))
  1722.   function               ; die Funktion
  1723.   wants-next-method-p    ; Flag, ob als erstes Argument die NEXT-METHOD (als
  1724.                          ; Funktion mit allen Argumenten) bzw. NIL ⁿbergeben
  1725.                          ; werden soll (= NIL bei :BEFORE- und :AFTER-Methoden)
  1726.   parameter-specializers ; Liste ({class | (EQL object)}*)
  1727.   qualifiers             ; Liste von Symbolen, z.B. (:before)
  1728.   signature              ; Liste (reqanz optanz restp keyp keywords allowp)
  1729.   gf                     ; die generische Funktion, zu der diese Methode
  1730.                          ; geh÷rt (nur fⁿr den Bedarf von NO-NEXT-METHOD)
  1731.   initfunction           ; liefert, wenn aufgerufen, die Funktion
  1732.                          ; (nur fⁿr den Bedarf von ADD-METHOD)
  1733. )
  1734.  
  1735. ; Bei NO-NEXT-METHOD mu▀ die generische Funktion bekannt sein. Da allerdings
  1736. ; im Prinzip Methoden nicht bestimmten generischen Funktionen zugeh÷rig sind
  1737. ; (wegen ADD-METHOD), mⁿssen wir die Methode bei ADD-METHOD kopieren. Die
  1738. ; IdentitΣt zweier Kopien derselben Methode stellen wir durch Blick auf
  1739. ; std-method-initfunction fest. (Man k÷nnte stattdessen auch die generische
  1740. ; Funktion bei jedem Aufruf mitgeben, als erstes Argument an die effektive
  1741. ; Methode, aber das ist sicher ineffizienter.)
  1742.  
  1743. (defun print-std-method (method stream depth)
  1744.   (declare (ignore depth))
  1745.   (print-unreadable-object (method stream :type t)
  1746.     (dolist (q (std-method-qualifiers method))
  1747.       (write q :stream stream)
  1748.       (write-char #\Space stream)
  1749.     )
  1750.     (write (std-method-parameter-specializers method) :stream stream)
  1751. ) )
  1752.  
  1753. ; Hilfsfunktion: Liefert eine Liste von n Gensyms.
  1754. (defun n-gensyms (n)
  1755.   (do ((l '() (cons (gensym) l))
  1756.        (i n (1- i)))
  1757.       ((eql i 0) l)
  1758. ) )
  1759.  
  1760. ; Hilfsfunktion: Testet auf Lambda-Listen-Marker.
  1761. (defun lambda-list-keyword-p (x)
  1762.   (memq x lambda-list-keywords)
  1763. )
  1764.  
  1765. ;; Fⁿr DEFMETHOD, DEFGENERIC, GENERIC-FUNCTION, GENERIC-FLET, GENERIC-LABELS,
  1766. ;; WITH-ADDED-METHODS
  1767.   ; caller: Symbol
  1768.   ; funname: Funktionsname, Symbol oder (SETF symbol)
  1769.   ; description: (qualifier* spec-lambda-list {declaration|docstring}* form*)
  1770.   ; ==> method-building-form
  1771. (defun analyze-method-description (caller funname description env)
  1772.   (let ((qualifiers nil))
  1773.     (loop
  1774.       (when (atom description)
  1775.         (error-of-type 'program-error
  1776.           (DEUTSCH "~S ~S: Lambdaliste fehlt."
  1777.            ENGLISH "~S ~S: missing lambda list"
  1778.            FRANCAIS "~S ~S : la liste lambda manque.")
  1779.           caller funname
  1780.       ) )
  1781.       (when (listp (car description)) (return))
  1782.       (push (pop description) qualifiers)
  1783.     )
  1784.     ; Nur STANDARD Methodenkombination ist implementiert.
  1785.     (cond ((equal qualifiers '()))
  1786.           ((equal qualifiers '(:before)))
  1787.           ((equal qualifiers '(:after)))
  1788.           ((equal qualifiers '(:around)))
  1789.           (t (error-of-type 'program-error
  1790.                (DEUTSCH "Bei STANDARD Methodenkombination dⁿrfen die Methodenbestimmer nicht ~S lauten."
  1791.                 ENGLISH "STANDARD method combination doesn't allow the method qualifiers to be ~S"
  1792.                 FRANCAIS "La combinaison STANDARD de mΘthodes ne permet pas de qualifier des mΘthodes comme ~S.")
  1793.                (nreverse qualifiers)
  1794.     )     )  )
  1795.     ; Lambdaliste bilden, Parameter-Specializer und Signatur extrahieren:
  1796.     (let ((specialized-lambda-list (car description))
  1797.           (body (cdr description)))
  1798.       (let ((req-vars '())
  1799.             (ignorable-req-vars '())
  1800.             (req-specializer-forms '()))
  1801.         (do ()
  1802.             ((or (atom specialized-lambda-list)
  1803.                  (lambda-list-keyword-p (car specialized-lambda-list))
  1804.             ))
  1805.           (let* ((item (pop specialized-lambda-list))
  1806.                  (specializer-name
  1807.                    (if (atom item)
  1808.                      (progn (push item req-vars) 't)
  1809.                      (progn
  1810.                        (push (first item) req-vars)
  1811.                        (push (first item) ignorable-req-vars) ; CLtL2 S. 840 oben
  1812.                        (second item)
  1813.                 )) ) )
  1814.             (push (if (and (consp specializer-name)
  1815.                            (eq (car specializer-name) 'EQL)
  1816.                       )
  1817.                     `(LIST 'EQL ,(second specializer-name))
  1818.                     `(FIND-CLASS ',specializer-name)
  1819.                   )
  1820.                   req-specializer-forms
  1821.         ) ) )
  1822.         (let* ((reqanz (length req-vars))
  1823.                (lambda-list (nreconc req-vars specialized-lambda-list))
  1824.                (optanz
  1825.                  (let ((h (cdr (member '&OPTIONAL lambda-list :test #'eq))))
  1826.                    (or (position-if #'lambda-list-keyword-p h) (length h))
  1827.                ) )
  1828.                (keyp (not (null (member '&KEY lambda-list :test #'eq))))
  1829.                (restp (or keyp (not (null (member '&REST lambda-list :test #'eq)))))
  1830.                (keywords
  1831.                  (mapcar
  1832.                    #'(lambda (item)
  1833.                        (when (consp item) (setq item (first item)))
  1834.                        (if (consp item)
  1835.                          (first item)
  1836.                          (intern (symbol-name item) *keyword-package*)
  1837.                      ) )
  1838.                    (let ((h (cdr (member '&KEY lambda-list :test #'eq))))
  1839.                      (subseq h 0 (position-if #'lambda-list-keyword-p h))
  1840.                ) ) )
  1841.                (allowp (and keyp (not (null (member '&ALLOW-OTHER-KEYS lambda-list :test #'eq)))))
  1842.               )
  1843.           ; Methoden haben ein implizites &allow-other-keys (28.1.6.4.):
  1844.           (when (and keyp (not allowp))
  1845.             (let ((index (+ (position '&KEY lambda-list :test #'eq) 1 (length keywords))))
  1846.               (setq lambda-list
  1847.                 `(,@(subseq lambda-list 0 index) &ALLOW-OTHER-KEYS
  1848.                   ,@(subseq lambda-list index)
  1849.                  )
  1850.           ) ) )
  1851.           (let* ((self (gensym))
  1852.                  (wants-next-method-p
  1853.                    (or (equal qualifiers '()) (equal qualifiers '(:around)))
  1854.                  )
  1855.                  (compile nil)
  1856.                  (lambdabody
  1857.                    (multiple-value-bind (body-rest declarations docstring)
  1858.                        (sys::parse-body body t env)
  1859.                      (declare (ignore docstring))
  1860.                      (setq compile (member '(COMPILE) declarations :test #'equal))
  1861.                      (when ignorable-req-vars
  1862.                        (push `(IGNORABLE ,@(nreverse ignorable-req-vars))
  1863.                              declarations
  1864.                      ) )
  1865.                      (let ((lambdabody-part1
  1866.                              `(,lambda-list
  1867.                                ,@(if declarations `((DECLARE ,@declarations)))
  1868.                               )
  1869.                            )
  1870.                            (lambdabody-part2
  1871.                              (if (eq caller 'generic-function)
  1872.                                body-rest
  1873.                                ; impliziter Block
  1874.                                `((BLOCK ,(block-name funname) ,@body-rest))
  1875.                           )) )
  1876.                        (if wants-next-method-p
  1877.                          (let ((cont (gensym)) ; Variable fⁿr die Continuation
  1878.                                (req-dummies ; Liste von reqanz Dummies
  1879.                                  (n-gensyms reqanz)
  1880.                                )
  1881.                                (rest-dummy (if (or restp (> optanz 0)) (gensym)))
  1882.                                (lambda-expr `(LAMBDA ,@lambdabody-part1 ,@lambdabody-part2)))
  1883.                            `(; neue Lambda-Liste:
  1884.                              (,cont
  1885.                               ,@req-dummies
  1886.                               ,@(if rest-dummy `(&REST ,rest-dummy) '())
  1887.                              )
  1888.                              (MACROLET
  1889.                                ((CALL-NEXT-METHOD (&REST NEW-ARG-EXPRS)
  1890.                                   (IF NEW-ARG-EXPRS
  1891.                                     (LIST 'IF ',cont
  1892.                                       (LIST* 'FUNCALL ',cont NEW-ARG-EXPRS)
  1893.                                       (LIST* '%NO-NEXT-METHOD ',self NEW-ARG-EXPRS)
  1894.                                     )
  1895.                                     ,(if rest-dummy
  1896.                                        `(LIST 'IF ',cont
  1897.                                           (LIST 'APPLY ',cont
  1898.                                             ,@(mapcar #'(lambda (x) `',x) req-dummies)
  1899.                                             ',rest-dummy
  1900.                                           )
  1901.                                           (LIST 'APPLY '(FUNCTION %NO-NEXT-METHOD)
  1902.                                             ',self
  1903.                                             ,@(mapcar #'(lambda (x) `',x) req-dummies)
  1904.                                             ',rest-dummy
  1905.                                         ) )
  1906.                                        `(LIST 'IF ',cont
  1907.                                           (LIST 'FUNCALL ',cont
  1908.                                             ,@(mapcar #'(lambda (x) `',x) req-dummies)
  1909.                                           )
  1910.                                           (LIST '%NO-NEXT-METHOD
  1911.                                             ',self
  1912.                                             ,@(mapcar #'(lambda (x) `',x) req-dummies)
  1913.                                         ) )
  1914.                                      )
  1915.                                 ) )
  1916.                                 (NEXT-METHOD-P () ',cont)
  1917.                                )
  1918.                                ; neuer Body:
  1919.                                ,(if rest-dummy
  1920.                                   `(APPLY (FUNCTION ,lambda-expr)
  1921.                                           ,@req-dummies ,rest-dummy
  1922.                                    )
  1923.                                   `(,lambda-expr ,@req-dummies)
  1924.                                 )
  1925.                             ))
  1926.                          )
  1927.                          `(,@lambdabody-part1
  1928.                            (MACROLET
  1929.                              ((CALL-NEXT-METHOD ()
  1930.                                 (ERROR-OF-TYPE 'PROGRAM-ERROR
  1931.                                   (DEUTSCH "~S ~S: ~S ist in ~S-Methoden nicht erlaubt."
  1932.                                    ENGLISH "~S ~S: ~S is invalid within ~S methods"
  1933.                                    FRANCAIS "~S ~S : ~S n'est pas permit dans des mΘthodes ~S.")
  1934.                                   ',caller ',funname 'CALL-NEXT-METHOD ',(first qualifiers)
  1935.                               ) )
  1936.                               (NEXT-METHOD-P ()
  1937.                                 (ERROR-OF-TYPE 'PROGRAM-ERROR
  1938.                                   (DEUTSCH "~S ~S: ~S ist in ~S-Methoden nicht erlaubt."
  1939.                                    ENGLISH "~S ~S: ~S is invalid within ~S methods"
  1940.                                    FRANCAIS "~S ~S : ~S n'est pas permit dans des mΘthodes ~S.")
  1941.                                   ',caller ',funname 'NEXT-METHOD-P ',(first qualifiers)
  1942.                              )) )
  1943.                              ,@lambdabody-part2
  1944.                           ))
  1945.                 )) ) ) )
  1946.             `(MAKE-STANDARD-METHOD
  1947.                :INITFUNCTION
  1948.                  #'(LAMBDA (,self)
  1949.                      ,@(if compile '((DECLARE (COMPILE))))
  1950.                      (%OPTIMIZE-FUNCTION-LAMBDA
  1951.                        ,(if wants-next-method-p `(T) `())
  1952.                        ,@lambdabody
  1953.                    ) )
  1954.                :WANTS-NEXT-METHOD-P ',wants-next-method-p
  1955.                :PARAMETER-SPECIALIZERS (LIST ,@(nreverse req-specializer-forms))
  1956.                :QUALIFIERS ',qualifiers
  1957.                :SIGNATURE '(,reqanz ,optanz ,restp ,keyp ,keywords ,allowp)
  1958.              )
  1959. ) ) ) ) ) )
  1960.  
  1961. ;; 28.1.6.3. agreement on parameter specializers and qualifiers
  1962. (defun methods-agree-p (method1 method2)
  1963.   (and (equal (std-method-qualifiers method1) (std-method-qualifiers method2))
  1964.        (specializers-agree-p (std-method-parameter-specializers method1)
  1965.                              (std-method-parameter-specializers method2)
  1966. ) )    )
  1967. (defun specializers-agree-p (specializers1 specializers2)
  1968.   (and (eql (length specializers1) (length specializers2))
  1969.        (every #'(lambda (parspec1 parspec2)
  1970.                   (or ; zwei gleiche Klassen?
  1971.                       (eq parspec1 parspec2)
  1972.                       ; zwei gleiche EQL-Specializer?
  1973.                       (and (consp parspec1) (consp parspec2)
  1974.                            (eql (second parspec1) (second parspec2))
  1975.                 ) )   )
  1976.               specializers1 specializers2
  1977. ) )    )
  1978.  
  1979. ;; 28.1.6.2. applicable methods
  1980. (defun method-applicable-p (method required-arguments)
  1981.   (every #'typep required-arguments (std-method-parameter-specializers method))
  1982. )
  1983.  
  1984. ;; 28.1.7.1. sorting the applicable methods by precedence order
  1985. (defun sort-applicable-methods (methods required-arguments argument-order)
  1986.   (sort (copy-list methods)
  1987.         #'(lambda (method1 method2) ; method1 < method2 ?
  1988.             (let ((specializers1 (std-method-parameter-specializers method1))
  1989.                   (specializers2 (std-method-parameter-specializers method2)))
  1990.               (dolist (arg-index argument-order nil)
  1991.                 (let ((arg (nth arg-index required-arguments))
  1992.                       (psp1 (nth arg-index specializers1))
  1993.                       (psp2 (nth arg-index specializers2)))
  1994.                   (if (consp psp1)
  1995.                     (if (consp psp2)
  1996.                       nil        ; (EQL x) = (EQL x)
  1997.                       (return t) ; (EQL x) < <class>  ==>  method1 < method2
  1998.                     )
  1999.                     (if (consp psp2)
  2000.                       (return nil) ; <class> > (EQL x)   ==>  method1 > method2
  2001.                       ; Zwei Klassen: vergleiche die Position in der CPL von arg:
  2002.                       (let* ((cpl (class-precedence-list (class-of arg)))
  2003.                              (pos1 (position psp1 cpl))
  2004.                              (pos2 (position psp2 cpl)))
  2005.                         (cond ((< pos1 pos2) (return t)) ; method1 < method2
  2006.                               ((> pos1 pos2) (return nil)) ; method1 > method2
  2007.                       ) )
  2008.           ) ) ) ) ) )
  2009. ) )
  2010.  
  2011. ; Fⁿr STANDARD Methodenkombination: Aufspalten der Methoden nach Qualifiern
  2012. (defun partition-method-list (methods)
  2013.   (let ((primary-methods '())
  2014.         (before-methods '())
  2015.         (after-methods '())
  2016.         (around-methods '()))
  2017.     (dolist (method methods)
  2018.       (let ((quals (std-method-qualifiers method)))
  2019.         (cond ((equal quals '())        (push method primary-methods))
  2020.               ((equal quals '(:before)) (push method before-methods))
  2021.               ((equal quals '(:after))  (push method after-methods))
  2022.               ((equal quals '(:around)) (push method around-methods))
  2023.     ) ) )
  2024.     (values
  2025.       (nreverse primary-methods)
  2026.       (nreverse before-methods)
  2027.       (nreverse after-methods)
  2028.       (nreverse around-methods)
  2029. ) ) )
  2030.  
  2031.  
  2032. ;;; Generische Funktionen
  2033.  
  2034. ; Low-Level-ReprΣsentation:
  2035. ; Compilierte Funktionen (Cclosures), bei denen im Flag-Byte des Code-Vektors
  2036. ; ein bestimmtes Bit gesetzt ist. Hintendran zusΣtzlich:
  2037. ; - die Signatur, eine Liste (reqanz optanz restp keywords allowp),
  2038. ; - die Argument-Precedence-Order, als Liste der Zahlen von 0 bis reqanz-1,
  2039. ; - die Liste aller Methoden.
  2040.  
  2041. ; Der Compiler benutzt (bei GENERIC-FLET, GENERIC-LABELS) und der Evaluator
  2042. ; setzt ebenfalls voraus, da▀ eine generische Funktion ihre Aufrufkonvention
  2043. ; nicht Σndert.
  2044. ; Eine generische Funktion mit Signatur (reqanz optanz restp keywords allowp)
  2045. ; ist von Anfang an (!) eine compilierte Funktion mit
  2046. ;         reqanz  required-Parametern
  2047. ;         0       optionalen Parametern
  2048. ;         &rest genau dann wenn (or (> optanz 0) restp),
  2049. ;         ohne &key.
  2050. (defun callinfo (reqanz optanz restp keywords allowp)
  2051.   (declare (ignore keywords allowp))
  2052.   (list reqanz 0 (or (> optanz 0) restp) nil nil nil)
  2053. )
  2054.  
  2055. (defun gf-signature (gf)
  2056.   (sys::%record-ref gf 3)
  2057. )
  2058. (defun (setf gf-signature) (new gf)
  2059.   (setf (sys::%record-ref gf 3) new)
  2060. )
  2061.  
  2062. (defun gf-argorder (gf)
  2063.   (sys::%record-ref gf 4)
  2064. )
  2065. (defun (setf gf-argorder) (new gf)
  2066.   (setf (sys::%record-ref gf 4) new)
  2067. )
  2068.  
  2069. (defun gf-methods (gf)
  2070.   (sys::%record-ref gf 5)
  2071. )
  2072. (defun (setf gf-methods) (new gf)
  2073.   (setf (sys::%record-ref gf 5) new)
  2074. )
  2075.  
  2076. ; Der Dispatch-Code fⁿr generische Funktionen wird mit
  2077. ; `(%GENERIC-FUNCTION-LAMBDA ,@lambdabody)
  2078. ; - Σhnlich zu `(FUNCTION (LAMBDA ,@lambdabody)) - gebildet.
  2079. ; Es dⁿrfen darin nicht vorkommen:
  2080. ; - Zugriff auf dynamische Variablen, Binden von dynamischen Variablen,
  2081. ; - nichttriviale BLOCK, RETURN-FROM, TAGBODY, GO Konstrukte,
  2082. ; - Aufruf globaler Funktionen, die nicht inline sind,
  2083. ; - Bildung von nicht-autonomen Funktionen (Closures).
  2084. ; N÷tig ist also:
  2085. ;   (declare (inline case eql eq typep
  2086. ;                    arrayp bit-vector-p characterp complexp consp floatp
  2087. ;                    functionp clos::generic-function-p hash-table-p integerp
  2088. ;                    listp null numberp packagep pathnamep sys::logical-pathname-p
  2089. ;                    random-state-p rationalp readtablep realp sys::sequencep
  2090. ;                    clos::std-instance-p streamp sys::file-stream-p
  2091. ;                    sys::synonym-stream-p sys::broadcast-stream-p
  2092. ;                    sys::concatenated-stream-p sys::two-way-stream-p
  2093. ;                    sys::echo-stream-p sys::string-stream-p stringp
  2094. ;                    clos::structure-instance-p symbolp vectorp
  2095. ;                    class-of cons gethash funcall apply ...
  2096. ;   )        )
  2097. ; Das Ergebnis ist nicht(!) als eigenstΣndige Funktion aufrufbar, sondern
  2098. ; bedarf der Nachbearbeitung: Die Konstanten C_0 ... C_(k-1) C_k mⁿssen zu
  2099. ; #(C_0 ... C_(k-1) . [Rest von C_k]) zusammengefa▀t werden, k = 0 oder 1.
  2100.  
  2101. ; Liefert eine generische Funktion ohne Dispatch-Code. Nicht aufrufbar!!
  2102. (let* ((prototype ; eine sinnlose Funktion
  2103.          #'(lambda (&rest args) (declare (compile) (ignore args))
  2104.              (tagbody 1 (go 1))
  2105.            )
  2106.        )
  2107.        (prototype-code (sys::%record-ref prototype 1)))
  2108.   (defun %make-gf (name signature argorder methods)
  2109.     (sys::%make-closure name prototype-code
  2110.                         (list nil signature argorder methods)
  2111.   ) )
  2112. )
  2113.  
  2114. #|
  2115. ; Besser in compiler.lsp??
  2116. (defun make-gf (name lambdabody signature argorder methods)
  2117.   (let ((preliminary
  2118.           (eval `(LET ()
  2119.                    (DECLARE (COMPILE))
  2120.                    (%GENERIC-FUNCTION-LAMBDA ,@lambdabody)
  2121.                  )
  2122.        )) )
  2123.     (sys::%make-closure
  2124.       name
  2125.       (sys::closure-codevec preliminary)
  2126.       (list
  2127.         (case (sys::%record-length preliminary)
  2128.           (3 (sys::%record-ref preliminary 2))
  2129.           (4 (let ((consts (sys::%record-ref preliminary 3)))
  2130.                (setf (svref consts 0) (sys::%record-ref preliminary 2))
  2131.                consts
  2132.         ) )  )
  2133.         signature
  2134.         argorder
  2135.         methods
  2136. ) ) ) )
  2137. |#
  2138.  
  2139.  
  2140. #|
  2141.  
  2142. ;; Generische Funktionen mit primitivem Dispatch:
  2143.  
  2144. (defun make-slow-gf (name signature argorder methods)
  2145.   (let* ((final (%make-gf name signature argorder methods))
  2146.          (preliminary
  2147.            (eval `(LET ((GF ',final))
  2148.                     (DECLARE (COMPILE))
  2149.                     (%GENERIC-FUNCTION-LAMBDA (&REST ARGS)
  2150.                       (DECLARE (INLINE APPLY))
  2151.                       (APPLY 'SLOW-FUNCALL-GF GF ARGS)
  2152.                   ) )
  2153.         )) )
  2154.     (setf (sys::%record-ref final 1) (sys::closure-codevec preliminary))
  2155.     (setf (sys::%record-ref final 2)
  2156.           (case (sys::%record-length preliminary)
  2157.             (3 (sys::%record-ref preliminary 2))
  2158.             (4 (let ((consts (sys::%record-ref preliminary 3)))
  2159.                  (setf (svref consts 0) (sys::%record-ref preliminary 2))
  2160.                  consts
  2161.           ) )  )
  2162.     )
  2163.     final
  2164. ) )
  2165.  
  2166. (let* ((prototype
  2167.          (let ((gf 'magic))
  2168.            (declare (compile))
  2169.            (%generic-function-lambda (&rest args)
  2170.              (declare (inline apply))
  2171.              (apply 'slow-funcall-gf gf args)
  2172.        ) ) )
  2173.        (prototype-code (sys::%record-ref prototype 1))
  2174.        (prototype-consts (sys::%record-ref prototype 3)))
  2175.   (defun finalize-slow-gf (gf)
  2176.     (setf (sys::%record-ref gf 1) prototype-code)
  2177.     (setf (sys::%record-ref gf 2) (substitute gf 'magic prototype-consts))
  2178.   )
  2179.   (defun gf-never-called-p (gf) (eq (sys::%record-ref gf 1) prototype-code))
  2180.   (defun warn-if-gf-already-called (gf) )
  2181. )
  2182.  
  2183. ; Aufruf einer generischen Funktion
  2184. (defun slow-funcall-gf (gf &rest args)
  2185.   (let ((reqanz (first (gf-signature gf)))
  2186.         (arg-order (gf-argorder gf))
  2187.         (methods (gf-methods gf)))
  2188.     (unless (>= (length args) reqanz)
  2189.       (error-of-type 'error
  2190.         (DEUTSCH "Zu wenig Argumente fⁿr ~S: ~S"
  2191.          ENGLISH "Too few arguments to ~S: ~S"
  2192.          FRANCAIS "Trop peu d'arguments pour ~S : ~S")
  2193.         gf args
  2194.     ) )
  2195.     (let ((req-args (subseq args 0 reqanz)))
  2196.       ; Determine the effective method:
  2197.       ; 1. Select the applicable methods:
  2198.       (setq methods
  2199.         (remove-if-not #'(lambda (method) (method-applicable-p method req-args))
  2200.                        methods
  2201.       ) )
  2202.       (when (null methods)
  2203.         (return-from slow-funcall-gf (apply #'no-applicable-method gf args))
  2204.       )
  2205.       ; 2. Sort the applicable methods by precedence order:
  2206.       (setq methods (sort-applicable-methods methods req-args arg-order))
  2207.       ; 3. Apply method combination:
  2208.       ; Nur STANDARD Methoden-Kombination ist implementiert.
  2209.       ; Aufspalten in einzelne Methoden-Typen:
  2210.       (multiple-value-bind (primary-methods before-methods after-methods around-methods)
  2211.           (partition-method-list methods)
  2212.         (when (null primary-methods)
  2213.           (return-from slow-funcall-gf (apply #'no-primary-method gf args))
  2214.         )
  2215.         ; Methoden zu einer "effektiven Methode" kombinieren:
  2216.         (labels ((ef-1 (primary-methods before-methods after-methods around-methods)
  2217.                    (if (null around-methods)
  2218.                      (ef-2 primary-methods before-methods after-methods)
  2219.                      (let* ((1method (first around-methods))
  2220.                             (1function (std-method-function 1method)))
  2221.                        (if (std-method-wants-next-method-p 1method)
  2222.                          (let ((next-ef
  2223.                                  (ef-1 primary-methods before-methods after-methods (rest around-methods))
  2224.                               ))
  2225.                            #'(lambda (&rest args) (apply 1function next-ef args))
  2226.                          )
  2227.                          #'(lambda (&rest args) (apply 1function args))
  2228.                  ) ) ) )
  2229.                  (ef-2 (primary-methods before-methods after-methods)
  2230.                    (if (null after-methods)
  2231.                      (ef-3 primary-methods before-methods)
  2232.                      (let* ((1method (first after-methods))
  2233.                             (1function (std-method-function 1method)))
  2234.                        (let ((next-ef (ef-2 primary-methods before-methods (rest after-methods))))
  2235.                          #'(lambda (&rest args) (multiple-value-prog1 (apply next-ef args) (apply 1function args)))
  2236.                  ) ) ) )
  2237.                  (ef-3 (primary-methods before-methods)
  2238.                    (if (null before-methods)
  2239.                      (ef-4 primary-methods)
  2240.                      (let* ((1method (first before-methods))
  2241.                             (1function (std-method-function 1method)))
  2242.                        (let ((next-ef (ef-3 primary-methods (rest before-methods))))
  2243.                          #'(lambda (&rest args) (progn (apply 1function args) (apply next-ef args)))
  2244.                  ) ) ) )
  2245.                  (ef-4 (primary-methods)
  2246.                    (if (null primary-methods)
  2247.                      nil ; keine Funktion, NEXT-METHOD-P reagiert darauf
  2248.                      (let* ((1method (first primary-methods))
  2249.                             (1function (std-method-function 1method)))
  2250.                        (if (std-method-wants-next-method-p 1method)
  2251.                          (let ((next-ef (ef-4 (rest primary-methods))))
  2252.                            #'(lambda (&rest args) (apply 1function next-ef args))
  2253.                          )
  2254.                          #'(lambda (&rest args) (apply 1function args))
  2255.                 )) ) ) )
  2256.           (let ((ef (ef-1 primary-methods before-methods after-methods around-methods)))
  2257.             ; Keyword-Check (28.1.6.4., 28.1.6.5.) ??
  2258.             ; Effektive Methode aufrufen:
  2259.             (funcall ef args)
  2260. ) ) ) ) ) )
  2261.  
  2262. |#
  2263.  
  2264.  
  2265. ;; Generische Funktionen mit optimiertem Dispatch:
  2266.  
  2267. (defun make-fast-gf (name signature argorder)
  2268.   (let ((gf (%make-gf name signature argorder '())))
  2269.     (finalize-fast-gf gf)
  2270.     gf
  2271. ) )
  2272.  
  2273. (let ((prototype-table (make-hash-table :test #'equal)))
  2274.   (defun finalize-fast-gf (gf)
  2275.     (let* ((signature (gf-signature gf))
  2276.            (reqanz (first signature))
  2277.            (restp (or (third signature) (> (second signature) 0)))
  2278.            (hash-key (cons reqanz restp))
  2279.            (prototype
  2280.              (or (gethash hash-key prototype-table)
  2281.                  (setf (gethash hash-key prototype-table)
  2282.                        (let* ((reqvars (n-gensyms reqanz))
  2283.                               (proto-gf
  2284.                                 (eval `(LET ((GF 'MAGIC))
  2285.                                          (DECLARE (COMPILE))
  2286.                                          (%GENERIC-FUNCTION-LAMBDA (,@reqvars ,@(if restp '(&REST ARGS) '()))
  2287.                                            (DECLARE (INLINE APPLY))
  2288.                                            (APPLY 'INITIAL-FUNCALL-GF GF ,@reqvars ,(if restp `ARGS `'NIL))
  2289.                                        ) )
  2290.                              )) )
  2291.                          ; (sys::%record-ref proto-gf 1) mⁿssen wir aufbewahren.
  2292.                          ; (sys::%record-ref proto-gf 3) = #(NIL INITIAL-FUNCALL-GF MAGIC)
  2293.                          (sys::%record-ref proto-gf 1)
  2294.           )) )   )     )
  2295.       (setf (sys::%record-ref gf 1) prototype)
  2296.       (setf (sys::%record-ref gf 2) (vector 'NIL 'INITIAL-FUNCALL-GF gf))
  2297.   ) )
  2298.   (defun gf-never-called-p (gf)
  2299.     (let* ((signature (gf-signature gf))
  2300.            (reqanz (first signature))
  2301.            (restp (or (third signature) (> (second signature) 0)))
  2302.            (hash-key (cons reqanz restp))
  2303.            (prototype (gethash hash-key prototype-table)))
  2304.       (eq (sys::%record-ref gf 1) prototype)
  2305.   ) )
  2306.   (defun warn-if-gf-already-called (gf)
  2307.     (unless (gf-never-called-p gf)
  2308.       (warn (DEUTSCH "Die generische Funktion ~S wird modifiziert, wurde aber bereits aufgerufen."
  2309.              ENGLISH "The generic function ~S is being modified, but has already been called."
  2310.              FRANCAIS "On change la fonction gΘnΘrique ~S qui a dΘjα ΘtΘ appelΘe.")
  2311.             gf
  2312.   ) ) )
  2313. )
  2314.  
  2315. ; Der eigentliche Dispatch-Code wird erst beim ersten Aufruf der funktion
  2316. ; berechnet, um aufeinanderfolgende Methoden-Definitionen nicht zu teuer
  2317. ; zu machen.
  2318.  
  2319. ; Erster Aufruf einer generischen Funktion:
  2320. (defun initial-funcall-gf (gf &rest args)
  2321.   (install-dispatch gf)
  2322.   (apply gf args)
  2323. )
  2324.  
  2325. ; Installiert den endgⁿltigen Dispatch-Code in eine generische Funktion.
  2326. (defun install-dispatch (gf)
  2327.   (multiple-value-bind (bindings lambdabody) (compute-dispatch gf)
  2328.     (let ((preliminary
  2329.             (eval `(LET ,bindings
  2330.                      (DECLARE (COMPILE))
  2331.                      (%GENERIC-FUNCTION-LAMBDA ,@lambdabody)
  2332.                    )
  2333.          )) )
  2334.       (setf (sys::%record-ref gf 1) (sys::%record-ref preliminary 1))
  2335.       (setf (sys::%record-ref gf 2)
  2336.             (let ((consts (sys::%record-ref preliminary 3)))
  2337.                (setf (svref consts 0) (sys::%record-ref preliminary 2))
  2338.                consts
  2339.       )     )
  2340. ) ) )
  2341.  
  2342. ; Berechnet den Dispatch-Code einer generischen Funktion.
  2343. ; Er hat folgendes Aussehen:
  2344. ; (LAMBDA (variablen)      ; die required einzeln, alles andere mit &rest
  2345. ;   (DECLARE (INLINE ...)) ; alles inline wegen %GENERIC-FUNCTION-LAMBDA
  2346. ;   If-Kaskaden, dabei werden EQL-Parameter-Specializer und die meisten
  2347. ;   Builtin-Klassen per TYPEP inline abgefragt.
  2348. ;   Fⁿr die anderen required-Parameter wird CLASS-OF aufgerufen, die Ergebnisse
  2349. ;   gesammelt und als Index in eine Hash-Tabelle genommen. Dort steht die
  2350. ;   effektive Methode:
  2351. ;   (LET ((EM (GETHASH (CONS (CLASS-OF ...) ...) ht1)))
  2352. ;     (WHEN EM (RETURN-FROM block (APPLY EM Argumente)))
  2353. ;   )
  2354. ;   Wenn das nicht gelungen ist:
  2355. ;   (APPLY 'COMPUTE-AND-ADD-EFFECTIVE-METHOD gf Argumente)
  2356. ; )
  2357. (defun compute-dispatch (gf)
  2358.   (let* ((signature (gf-signature gf))
  2359.          (req-anz (first signature))
  2360.          (req-vars (n-gensyms req-anz))
  2361.          (restp (or (third signature) (> (second signature) 0)))
  2362.          (rest-var (if restp (gensym)))
  2363.          (apply-fun (if restp 'APPLY 'FUNCALL))
  2364.          (apply-args `(,@req-vars ,@(if restp `(,rest-var) '())))
  2365.          (arg-order (gf-argorder gf))
  2366.          (methods (gf-methods gf))
  2367.          (block-name (gensym))
  2368.          (maybe-no-applicable nil)
  2369.          (ht-vars '())) ; Liste von Hashtabellen-Variablen und ihren Inits
  2370.     ; Wir machen eine Rekursion ⁿber die Argumente.
  2371.     (labels
  2372.        ((recursion (remaining-args ; ein nthcdr von arg-order
  2373.                     remaining-methods ; Teilliste von methods
  2374.                     class-of-exprs ; Liste von CLASS-OF Expressions
  2375.                    )
  2376.           (if (null remaining-methods)
  2377.             (progn
  2378.               (setq maybe-no-applicable t)
  2379.               'NIL ; nichts tun, spΣter NO-APPLICABLE-METHOD aufrufen
  2380.             )
  2381.             (if (null remaining-args)
  2382.               ; alle Argumente abgearbeitet
  2383.               #| ; benutze GETHASH :
  2384.               (let ((ht-var (gensym))
  2385.                     (n (length class-of-exprs)) ; indiziere mit n-Tupeln
  2386.                     ht-init ; Expression zum Initialisieren von ht-var
  2387.                     ht-key-binding ; Bindung einer Variablen an ein n-Tupel
  2388.                     em-expr ; Expression zum Auffinden der EM
  2389.                     setf-em-expr ; Expression-Teil zum Setzen der EM
  2390.                    )
  2391.                 (if (eql n 0)
  2392.                   (setq ht-init 'NIL
  2393.                         ht-key-binding '()
  2394.                         em-expr ht-var
  2395.                         setf-em-expr `(SETQ ,ht-var)
  2396.                   )
  2397.                   (let ((tuple-var (gensym)))
  2398.                     (setq ht-init
  2399.                           `(MAKE-HASH-TABLE
  2400.                              :TEST (FUNCTION ,(if (eql n 1) 'EQ 'EQUAL))
  2401.                            )
  2402.                           ht-key-binding
  2403.                           `((,tuple-var
  2404.                              ,(let ((tuple-fun (hash-tuple-function n)))
  2405.                                 (if (member '&rest (second tuple-fun))
  2406.                                   `(,tuple-fun ,@(reverse class-of-exprs))
  2407.                                   ; kein &rest -> kann optimieren
  2408.                                   ; (der Compiler kann's noch nicht so gut)
  2409.                                   (sublis (mapcar #'cons (second tuple-fun) (reverse class-of-exprs))
  2410.                                           (third tuple-fun)
  2411.                               ) ) )
  2412.                            ))
  2413.                           em-expr
  2414.                           `(GETHASH ,tuple-var ,ht-var)
  2415.                           setf-em-expr
  2416.                           ; `(SETF (GETHASH ,tuple-var ,ht-var)) ginge auch;
  2417.                           ; das Folgende spart aber zwei temporΣre Variablen:
  2418.                           `(SYSTEM::PUTHASH ,tuple-var ,ht-var)
  2419.                 ) ) )
  2420.                 (push (list ht-var ht-init) ht-vars)
  2421.                 `(LET ,ht-key-binding
  2422.                    (RETURN-FROM ,block-name
  2423.                      (,apply-fun
  2424.                       (OR ,em-expr
  2425.                           (,@setf-em-expr
  2426.                                 (,apply-fun 'COMPUTE-EFFECTIVE-METHOD ',gf
  2427.                                             ,@apply-args
  2428.                       )   )     )
  2429.                       ,@apply-args
  2430.                  ) ) )
  2431.               )
  2432.               |# ; benutze CLASS-GETHASH und CLASS-TUPLE-GETHASH :
  2433.               (let ((ht-var (gensym))
  2434.                     (n (length class-of-exprs)) ; indiziere mit n-Tupeln
  2435.                     ht-init ; Expression zum Initialisieren von ht-var
  2436.                     em-expr ; Expression zum Auffinden der EM
  2437.                     setf-em-expr ; Expression-Teil zum Setzen der EM
  2438.                    )
  2439.                 (if (eql n 0)
  2440.                   (setq ht-init 'NIL
  2441.                         em-expr ht-var
  2442.                         setf-em-expr `(SETQ ,ht-var)
  2443.                   )
  2444.                   (setq class-of-exprs
  2445.                         (reverse class-of-exprs)
  2446.                         ht-init
  2447.                         `(MAKE-HASH-TABLE
  2448.                            :TEST (FUNCTION ,(if (eql n 1) 'EQ 'EQUAL))
  2449.                          )
  2450.                         em-expr
  2451.                         (if (eql n 1) ; je nachdem welches schneller ist
  2452.                           ; `(GETHASH ,@class-of-exprs ,ht-var) ==
  2453.                           `(CLASS-GETHASH ,ht-var ,(second (first class-of-exprs)))
  2454.                           `(CLASS-TUPLE-GETHASH ,ht-var ,@(mapcar #'second class-of-exprs))
  2455.                         )
  2456.                         setf-em-expr
  2457.                         `(SYSTEM::PUTHASH
  2458.                           ,(let ((tuple-fun (hash-tuple-function n)))
  2459.                              (if (member '&rest (second tuple-fun))
  2460.                                `(,tuple-fun ,@class-of-exprs)
  2461.                                ; kein &rest -> kann optimieren
  2462.                                ; (der Compiler kann's noch nicht so gut)
  2463.                                (sublis (mapcar #'cons (second tuple-fun) class-of-exprs)
  2464.                                        (third tuple-fun)
  2465.                            ) ) )
  2466.                           ,ht-var
  2467.                          )
  2468.                 ) )
  2469.                 (push (list ht-var ht-init) ht-vars)
  2470.                 `(RETURN-FROM ,block-name
  2471.                    (,apply-fun
  2472.                     (OR ,em-expr
  2473.                         (,@setf-em-expr
  2474.                               (,apply-fun 'COMPUTE-EFFECTIVE-METHOD ',gf
  2475.                                           ,@apply-args
  2476.                     )   )     )
  2477.                     ,@apply-args
  2478.                  ) )
  2479.               )
  2480.               ; nΣchstes Argument abarbeiten:
  2481.               (let* ((arg-index (first remaining-args))
  2482.                      (arg-var (nth arg-index req-vars))
  2483.                      (eql-cases ; alle EQL-Specializer fⁿr dieses Argument
  2484.                        (remove-duplicates
  2485.                          (mapcar #'second
  2486.                            (remove-if-not #'consp
  2487.                              (mapcar #'(lambda (m)
  2488.                                          (nth arg-index
  2489.                                            (std-method-parameter-specializers m)
  2490.                                        ) )
  2491.                                remaining-methods
  2492.                          ) ) )
  2493.                          :test #'eql
  2494.                      ) )
  2495.                      (eql-caselist ; Fall-Liste fⁿr CASE
  2496.                        (mapcar
  2497.                          #'(lambda (object)
  2498.                              `((,object)
  2499.                                ,(recursion
  2500.                                   (cdr remaining-args)
  2501.                                   (remove-if-not
  2502.                                     #'(lambda (m)
  2503.                                         (typep object
  2504.                                           (nth arg-index
  2505.                                             (std-method-parameter-specializers m)
  2506.                                       ) ) )
  2507.                                     remaining-methods
  2508.                                   )
  2509.                                   class-of-exprs
  2510.                                 )
  2511.                               )
  2512.                            )
  2513.                          eql-cases
  2514.                     )) )
  2515.                 ; Fⁿrs weitere brauchen wir die EQL-Methoden nicht mehr zu
  2516.                 ; betrachten.
  2517.                 (setq remaining-methods
  2518.                       (remove-if
  2519.                         #'(lambda (m)
  2520.                             (consp
  2521.                               (nth arg-index
  2522.                                 (std-method-parameter-specializers m)
  2523.                           ) ) )
  2524.                         remaining-methods
  2525.                 )     )
  2526.                 ((lambda (other-cases)
  2527.                    (if eql-caselist
  2528.                      `(CASE ,arg-var ,@eql-caselist (T ,other-cases))
  2529.                      other-cases
  2530.                  ) )
  2531.                  (let ((classes
  2532.                          (delete <t>
  2533.                            (delete-duplicates
  2534.                              (mapcar #'(lambda (m)
  2535.                                          (nth arg-index
  2536.                                            (std-method-parameter-specializers m)
  2537.                                        ) )
  2538.                                      remaining-methods
  2539.                       )) ) ) )
  2540.                    ; Falls alle Klassen, auf die zu testen ist,
  2541.                    ; Built-In-Klassen sind, machen wir den Typ-Dispatch
  2542.                    ; inline. Denn in der Hierarchie der Built-In-Klassen
  2543.                    ; (die au▀er NULL und VECTOR keine mehrfache Vererbung
  2544.                    ; kennt) sind alle CPLs konsistent. Man kann daher mit
  2545.                    ; (subclassp (class-of obj) class) == (typep obj class)
  2546.                    ; arbeiten.
  2547.                    ; Im anderen Fall ist sowieso ein Hash-Tabellen-Zugriff
  2548.                    ; n÷tig, dann sparen wir uns den Test auf die Built-In-
  2549.                    ; Klassen und beziehen ihn in die Hash-Tabelle ein.
  2550.                    (if (and (every #'bc-p classes)
  2551.                             (<= (length classes) 5) ; zu viele FΣlle -> hashen
  2552.                        )
  2553.                      (labels
  2554.                         ((built-in-subtree (class remaining-classes remaining-methods)
  2555.                            ; behandelt die FΣlle, da▀ das Argument der Klasse
  2556.                            ; class angeh÷rt und auf Zugeh÷rigkeit zu einer der
  2557.                            ; remaining-classes abgeprⁿft werden mu▀.
  2558.                            ; (Man kann voraussetzen, da▀ (bc-and class x) /= nil
  2559.                            ; fⁿr alle x aus remaining-classes.)
  2560.                            (if (null remaining-classes)
  2561.                              ; Keine Fallunterscheidung mehr n÷tig
  2562.                              (recursion
  2563.                                (cdr remaining-args)
  2564.                                (remove-if-not
  2565.                                  #'(lambda (m)
  2566.                                      (bc-and class
  2567.                                        (nth arg-index
  2568.                                          (std-method-parameter-specializers m)
  2569.                                    ) ) )
  2570.                                  remaining-methods
  2571.                                )
  2572.                                class-of-exprs
  2573.                              )
  2574.                              ; Fallunterscheidung mittels TYPEP
  2575.                              (let ((test-class (first remaining-classes)))
  2576.                                ; besser test-class maximal wΣhlen:
  2577.                                (loop
  2578.                                  (let ((other-class
  2579.                                          (find-if
  2580.                                            #'(lambda (x)
  2581.                                                (and (subclassp test-class x)
  2582.                                                     (not (eq test-class x))
  2583.                                              ) )
  2584.                                            remaining-classes
  2585.                                       )) )
  2586.                                    (unless other-class (return))
  2587.                                    (setq test-class other-class)
  2588.                                ) )
  2589.                                `(IF (TYPEP ,arg-var ',(class-classname test-class))
  2590.                                   ,(built-in-subtree
  2591.                                      (bc-and class test-class) ; /= nil !
  2592.                                      (remove 'nil
  2593.                                        (mapcar
  2594.                                          #'(lambda (x) (bc-and x test-class))
  2595.                                          (remove test-class remaining-classes)
  2596.                                      ) )
  2597.                                      (remove-if-not
  2598.                                        #'(lambda (m)
  2599.                                            (bc-and
  2600.                                              (nth arg-index
  2601.                                                (std-method-parameter-specializers m)
  2602.                                              )
  2603.                                              test-class
  2604.                                          ) )
  2605.                                        remaining-methods
  2606.                                    ) )
  2607.                                   ,(built-in-subtree
  2608.                                      (bc-and-not class test-class) ; /= nil !
  2609.                                      (remove 'nil
  2610.                                        (mapcar
  2611.                                          #'(lambda (x) (bc-and-not x test-class))
  2612.                                          remaining-classes
  2613.                                      ) )
  2614.                                      (remove-if-not
  2615.                                        #'(lambda (m)
  2616.                                            (bc-and-not
  2617.                                              (nth arg-index
  2618.                                                (std-method-parameter-specializers m)
  2619.                                              )
  2620.                                              test-class
  2621.                                          ) )
  2622.                                        remaining-methods
  2623.                                    ) )
  2624.                                 )
  2625.                         )) ) )
  2626.                        (built-in-subtree <t> classes remaining-methods)
  2627.                      )
  2628.                      (recursion
  2629.                        (cdr remaining-args)
  2630.                        remaining-methods
  2631.                        (cons `(CLASS-OF ,arg-var) class-of-exprs)
  2632.                 )) ) )
  2633.        )) ) ) )
  2634.       (let ((form (recursion arg-order methods '())))
  2635.         (values
  2636.           ; bindings
  2637.           (nreverse ht-vars)
  2638.           ; lambdabody
  2639.           `((,@req-vars ,@(if restp `(&REST ,rest-var) '()))
  2640.             (DECLARE
  2641.               (INLINE ; fⁿr die Fallunterscheidungen:
  2642.                       CASE EQL EQ TYPEP
  2643.                       ; bei der Inline-Expansion von TYPEP auf Built-In-Klassen:
  2644.                       ARRAYP BIT-VECTOR-P CHARACTERP COMPLEXP CONSP FLOATP
  2645.                       FUNCTIONP CLOS::GENERIC-FUNCTION-P HASH-TABLE-P INTEGERP
  2646.                       LISTP NULL NUMBERP PACKAGEP PATHNAMEP SYS::LOGICAL-PATHNAME-P
  2647.                       RANDOM-STATE-P RATIONALP READTABLEP REALP SYS::SEQUENCEP
  2648.                       CLOS::STD-INSTANCE-P STREAMP SYS::FILE-STREAM-P
  2649.                       SYS::SYNONYM-STREAM-P SYS::BROADCAST-STREAM-P
  2650.                       SYS::CONCATENATED-STREAM-P SYS::TWO-WAY-STREAM-P
  2651.                       SYS::ECHO-STREAM-P SYS::STRING-STREAM-P STRINGP
  2652.                       CLOS::STRUCTURE-INSTANCE-P SYMBOLP VECTORP
  2653.                       ; Finden und Aufruf der effektiven Methode:
  2654.                       CLASS-OF CONS GETHASH CLASS-GETHASH CLASS-TUPLE-GETHASH
  2655.                       SYS::PUTHASH FUNCALL APPLY
  2656.             ) )
  2657.             (BLOCK ,block-name
  2658.               ,form
  2659.               ,@(if maybe-no-applicable
  2660.                   `((,apply-fun 'NO-APPLICABLE-METHOD ',gf ,@apply-args))
  2661.                 )
  2662.            ))
  2663. ) ) ) ) )
  2664.  
  2665. ; Unsere EQUAL-Hashfunktion schaut in Cons-BΣume nur bis Tiefe 4 hinein.
  2666. ; Ein Tupel aus maximal 16 Elementen kann zu einem solchen Baum gemacht werden.
  2667. (defun hash-tuple-function (n) ; n>0
  2668.   (case n
  2669.     (1 '(lambda (t1) t1))
  2670.     (2 '(lambda (t1 t2) (cons t1 t2)))
  2671.     (3 '(lambda (t1 t2 t3) (cons t1 (cons t2 t3))))
  2672.     (4 '(lambda (t1 t2 t3 t4) (cons (cons t1 t2) (cons t3 t4))))
  2673.     (5 '(lambda (t1 t2 t3 t4 t5) (cons (cons t1 t2) (cons t3 (cons t4 t5)))))
  2674.     (6 '(lambda (t1 t2 t3 t4 t5 t6)
  2675.           (cons (cons t1 t2) (cons (cons t3 t4) (cons t5 t6))) ))
  2676.     (7 '(lambda (t1 t2 t3 t4 t5 t6 t7)
  2677.           (cons (cons t1 (cons t2 t3)) (cons (cons t4 t5) (cons t6 t7))) ))
  2678.     (8 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8)
  2679.           (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons t7 t8))) ))
  2680.     (9 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9)
  2681.           (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons t7 (cons t8 t9)))) ))
  2682.     (10 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10)
  2683.            (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons (cons t7 t8) (cons t9 t10)))) ))
  2684.     (11 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11)
  2685.            (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 (cons t6 t7)) (cons (cons t8 t9) (cons t10 t11)))) ))
  2686.     (12 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12)
  2687.            (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons (cons t5 t6) (cons t7 t8)) (cons (cons t9 t10) (cons t11 t12)))) ))
  2688.     (13 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13)
  2689.            (cons (cons (cons t1 t2) (cons t3 (cons t4 t5))) (cons (cons (cons t6 t7) (cons t8 t9)) (cons (cons t10 t11) (cons t12 t13)))) ))
  2690.     (14 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14)
  2691.            (cons (cons (cons t1 t2) (cons (cons t3 t4) (cons t5 t6))) (cons (cons (cons t7 t8) (cons t9 t10)) (cons (cons t11 t12) (cons t13 t14)))) ))
  2692.     (15 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15)
  2693.            (cons (cons (cons t1 (cons t2 t3)) (cons (cons t4 t5) (cons t6 t7))) (cons (cons (cons t8 t9) (cons t10 t11)) (cons (cons t12 t13) (cons t14 t15)))) ))
  2694.     (16 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16)
  2695.            (cons (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons t7 t8))) (cons (cons (cons t9 t10) (cons t11 t12)) (cons (cons t13 t14) (cons t15 t16)))) ))
  2696.     (t '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 &rest more-t)
  2697.           (cons (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons t7 t8))) (cons (cons (cons t9 t10) (cons t11 t12)) (cons (cons t13 t14) more-t))) ))
  2698. ) )
  2699.  
  2700. ; Berechnet die effektive Methode zu gegebenen Argumenten.
  2701. ; Es ist eigentlich die effektive Methode zu allen Argumenten, die dieselben
  2702. ; EQL- und Klassen-EinschrΣnkungen haben wie die gegebenen Argumente, aber
  2703. ; darum hat sich compute-dispatch schon gekⁿmmert.
  2704. (defun compute-effective-method (gf &rest args)
  2705.   (tagbody restart-compute
  2706.     (return-from compute-effective-method
  2707.       (let* ((signature (gf-signature gf))
  2708.              (req-anz (first signature))
  2709.              (req-vars (n-gensyms req-anz))
  2710.              (req-args (subseq args 0 req-anz))
  2711.              (restp (or (third signature) (> (second signature) 0)))
  2712.              (rest-var (if restp (gensym)))
  2713.              (apply-fun (if restp 'APPLY 'FUNCALL))
  2714.              (apply-args `(,@req-vars ,@(if restp `(,rest-var) '())))
  2715.              (lambdalist `(,@req-vars ,@(if restp `(&REST ,rest-var) '())))
  2716.              (opt-vars '())
  2717.              (key-vars '())
  2718.              (lambdalist-keypart '())
  2719.              (arg-order (gf-argorder gf))
  2720.              (methods (gf-methods gf)))
  2721.         ; Determine the effective method:
  2722.         ; 1. Select the applicable methods:
  2723.         (setq methods
  2724.           (remove-if-not #'(lambda (method) (method-applicable-p method req-args))
  2725.                          methods
  2726.         ) )
  2727.         (when (null methods)
  2728.           (apply #'no-applicable-method gf args)
  2729.           (go restart-compute)
  2730.         )
  2731.         ; 28.1.6.4., 28.1.6.5.: Keyword arguments in generic functions
  2732.         (when restp
  2733.           ; Die generische Funktion hat &REST oder &KEY, also auch alle Methoden.
  2734.           ; "If the lambda-list of ... the generic function definition contains
  2735.           ;  &allow-other-keys, all keyword arguments are accepted."
  2736.           (unless (fifth signature)
  2737.             ; "The specific set of keyword arguments accepted ... varies according
  2738.             ;  to the applicable methods."
  2739.             (let ((signatures (mapcar #'std-method-signature methods)))
  2740.               ; "A method that has &rest but not &key does not affect the set of
  2741.               ;  acceptable keyword srguments."
  2742.               (setq signatures (delete-if-not #'fourth signatures))
  2743.               ; Keine Methode mit &key -> keine EinschrΣnkung der Argumente.
  2744.               (unless (null signatures)
  2745.                 ; "If the lambda-list of any applicable method ... contains
  2746.                 ;  &allow-other-keys, all keyword arguments are accepted."
  2747.                 (unless (some #'sixth signatures)
  2748.                   ; "The set of keyword arguments accepted for a particular call
  2749.                   ;  is the union of the keyword arguments accepted by all
  2750.                   ;  applicable methods and the keyword arguments mentioned after
  2751.                   ;  &key in the generic function definition."
  2752.                   (let ((keywords
  2753.                           (remove-duplicates
  2754.                             (append (fourth signature) (mapcap #'fifth signatures))
  2755.                             :from-end t
  2756.                        )) )
  2757.                     (setq opt-vars (n-gensyms (second signature)))
  2758.                     (setq key-vars (n-gensyms (length keywords)))
  2759.                     (setq lambdalist-keypart
  2760.                           `(&KEY
  2761.                             ,@(mapcar #'(lambda (kw var) `((,kw ,var)))
  2762.                                       keywords key-vars
  2763.                               )
  2764.                            )
  2765.         ) ) ) ) ) ) )
  2766.         ; 2. Sort the applicable methods by precedence order:
  2767.         (setq methods (sort-applicable-methods methods req-args arg-order))
  2768.         ; 3. Apply method combination:
  2769.         ; Nur STANDARD Methoden-Kombination ist implementiert.
  2770.         ; Aufspalten in einzelne Methoden-Typen:
  2771.         (multiple-value-bind (primary-methods before-methods after-methods around-methods)
  2772.             (partition-method-list methods)
  2773.           (when (null primary-methods)
  2774.             (apply #'no-primary-method gf args)
  2775.             (go restart-compute)
  2776.           )
  2777.           ; Methoden zu einer "effektiven Methode" kombinieren:
  2778.           (labels ((ef-1 (primary-methods before-methods after-methods around-methods)
  2779.                      (if (null around-methods)
  2780.                        (ef-2 primary-methods before-methods after-methods)
  2781.                        (let* ((1method (first around-methods))
  2782.                               (1function (std-method-function 1method)))
  2783.                          (if (std-method-wants-next-method-p 1method)
  2784.                            (let ((next-ef
  2785.                                      (ef-1 primary-methods before-methods after-methods (rest around-methods))
  2786.                                 ))
  2787.                              `(,apply-fun ',1function
  2788.                                           #'(LAMBDA ,lambdalist ,next-ef)
  2789.                                           ,@apply-args
  2790.                               )
  2791.                            )
  2792.                            `(,apply-fun ',1function ,@apply-args)
  2793.                    ) ) ) )
  2794.                    (ef-2 (primary-methods before-methods after-methods)
  2795.                      (let ((next-ef (ef-3 primary-methods after-methods)))
  2796.                        (if (null before-methods)
  2797.                          next-ef
  2798.                          `(PROGN
  2799.                             ,@(mapcar
  2800.                                 #'(lambda (method)
  2801.                                     `(,apply-fun ',(std-method-function method)
  2802.                                                  ,@apply-args
  2803.                                      )
  2804.                                   )
  2805.                                 before-methods ; most-specific-first
  2806.                               )
  2807.                             ,next-ef
  2808.                           )
  2809.                    ) ) )
  2810.                    (ef-3 (primary-methods after-methods)
  2811.                      (let ((next-ef (ef-4 primary-methods)))
  2812.                        (if (null after-methods)
  2813.                          next-ef
  2814.                          `(MULTIPLE-VALUE-PROG1
  2815.                             ,next-ef
  2816.                             ,@(mapcar
  2817.                                 #'(lambda (method)
  2818.                                     `(,apply-fun ',(std-method-function method)
  2819.                                                  ,@apply-args
  2820.                                      )
  2821.                                   )
  2822.                                 (reverse after-methods) ; most-specific-last
  2823.                               )
  2824.                           )
  2825.                    ) ) )
  2826.                    (ef-4 (primary-methods)
  2827.                      (let* ((1method (first primary-methods))
  2828.                             (1function (std-method-function 1method)))
  2829.                        (if (std-method-wants-next-method-p 1method)
  2830.                          (let ((next-ef-fun (ef-5 (rest primary-methods))))
  2831.                            `(,apply-fun ',1function ,next-ef-fun ,@apply-args)
  2832.                          )
  2833.                          `(,apply-fun ',1function ,@apply-args)
  2834.                    ) ) )
  2835.                    (ef-5 (primary-methods)
  2836.                      (if (null primary-methods)
  2837.                        'NIL ; keine Funktion, NEXT-METHOD-P reagiert darauf
  2838.                        `#'(LAMBDA ,lambdalist ,(ef-4 primary-methods))
  2839.                   )) )
  2840.             (let* ((ef-form (ef-1 primary-methods before-methods after-methods around-methods))
  2841.                    (ef-fun (if (and (eq (car ef-form) apply-fun)
  2842.                                     (equal (cddr ef-form) apply-args)
  2843.                                     (null lambdalist-keypart)
  2844.                                )
  2845.                              (cadr ef-form)
  2846.                              `#'(LAMBDA
  2847.                                   ,@(if (null opt-vars)
  2848.                                       `(,(append lambdalist lambdalist-keypart)
  2849.                                         ,@(if key-vars `((DECLARE (IGNORE ,@key-vars))))
  2850.                                        )
  2851.                                       `(,lambdalist
  2852.                                         (APPLY #'(LAMBDA (&OPTIONAL ,@opt-vars ,@lambdalist-keypart)
  2853.                                                    (DECLARE (IGNORE ,@opt-vars ,@key-vars))
  2854.                                                  )
  2855.                                                ,rest-var
  2856.                                        ))
  2857.                                     )
  2858.                                   ,ef-form
  2859.                                 )
  2860.                   ))       )
  2861.               ; (eval ef-fun)                                 ; interpretiert
  2862.               ; (eval `(LOCALLY (DECLARE (COMPILE)) ,ef-fun)) ; compiliert
  2863.               (eval `(LET () (DECLARE (COMPILE) (INLINE FUNCALL APPLY)) ,ef-fun))
  2864. ) ) ) ) ) ) )
  2865.  
  2866.  
  2867. ; Grausamer Hack (28.1.9.2.):
  2868. ; MAKE-INSTANCE mu▀ ⁿber die Methoden von INITIALIZE-INSTANCE und
  2869. ; SHARED-INITIALIZE Bescheid wissen.
  2870. ; REINITIALIZE-INSTANCE mu▀ ⁿber die Methoden von REINITIALIZE-INSTANCE und
  2871. ; SHARED-INITIALIZE Bescheid wissen.
  2872. (defvar |#'initialize-instance| nil)
  2873. (defvar |#'reinitialize-instance| nil)
  2874. (defvar |#'shared-initialize| nil)
  2875.  
  2876. ; Hinzufⁿgen einer Methode zu einer generischen Funktion:
  2877. (defun std-add-method (gf method)
  2878.   ; 28.1.6.4. congruent lambda lists
  2879.   (let ((gf-sign (gf-signature gf))             ; (reqanz optanz restp keywords allowp)
  2880.         (m-sign (std-method-signature method))) ; (reqanz optanz restp keyp keywords allowp)
  2881.     (unless (= (first m-sign) (first gf-sign))
  2882.       (error-of-type 'error
  2883.         (DEUTSCH "~S hat ~S, ~S hat aber ~S Required-Parameter."
  2884.          ENGLISH "~S has ~S, but ~S has ~S required parameters"
  2885.          FRANCAIS "~S reτoit ~S arguments obligatoires, mais ~S en reτoit ~S.")
  2886.         method (first m-sign) gf (first gf-sign)
  2887.     ) )
  2888.     (unless (= (second m-sign) (second gf-sign))
  2889.       (error-of-type 'error
  2890.         (DEUTSCH "~S hat ~S, ~S hat aber ~S optionale Parameter."
  2891.          ENGLISH "~S has ~S, but ~S has ~S optional parameters"
  2892.          FRANCAIS "~S reτoit ~S arguments facultatifs, mais ~S en reτoit ~S.")
  2893.         method (second m-sign) gf (second gf-sign)
  2894.     ) )
  2895.     (when (and (third m-sign) (not (third gf-sign)))
  2896.       (error-of-type 'error
  2897.         (DEUTSCH "~S hat &REST oder &KEY, ~S jedoch nicht."
  2898.          ENGLISH "~S has &REST or &KEY, but ~S hasn't."
  2899.          FRANCAIS "~S spΘcifie &REST ou &KEY, mais ~S pas.")
  2900.         method gf
  2901.     ) )
  2902.     (when (and (third gf-sign) (not (third m-sign)))
  2903.       (error-of-type 'error
  2904.         (DEUTSCH "~S hat &REST oder &KEY, ~S jedoch nicht."
  2905.          ENGLISH "~S has &REST or &KEY, but ~S hasn't."
  2906.          FRANCAIS "~S spΘcifie &REST ou &KEY, mais ~S pas.")
  2907.         gf method
  2908.     ) )
  2909.     (when (fourth gf-sign) ; gf hat Keywords?
  2910.       ; ja -> Methode mu▀ sie akzeptieren:
  2911.       (unless (if (fourth m-sign) ; Methode hat &key ?
  2912.                 (or (sixth m-sign) ; Methode mu▀ &allow-other-keys haben oder
  2913.                     (subsetp (fourth gf-sign) (fifth m-sign)) ; die Keywords aufzΣhlen
  2914.                 )
  2915.                 (third m-sign) ; Methode mu▀ &rest haben!
  2916.               )
  2917.         (error-of-type 'error
  2918.           (DEUTSCH "~S akzeptiert die Keywords ~S von ~S nicht."
  2919.            ENGLISH "~S doesn't accept the keywords ~S of ~S"
  2920.            FRANCAIS "~S n'accepte pas les mots clΘ ~S de ~S.")
  2921.           method (fourth gf-sign) gf
  2922.     ) ) )
  2923.   )
  2924.   ; method kopieren, damit man gf eintragen kann:
  2925.   (when (std-method-wants-next-method-p method)
  2926.     (setq method (copy-standard-method method))
  2927.     (setf (std-method-function method) nil)
  2928.     (setf (std-method-gf method) gf)
  2929.   )
  2930.   ; function aus initfunction bestimmen:
  2931.   (when (null (std-method-function method))
  2932.     (let ((h (funcall (std-method-initfunction method) method)))
  2933.       (setf (std-method-function method) (car h))
  2934.       (when (car (cdr h)) ; konnte die Variable ",cont" wegoptimiert werden?
  2935.         (setf (std-method-wants-next-method-p method) nil)
  2936.   ) ) )
  2937.   ; Methode ist fertig. Eintragen:
  2938.   (warn-if-gf-already-called gf)
  2939.   (let ((old-method (find method (gf-methods gf) :test #'methods-agree-p)))
  2940.     (cond ((eq gf |#'initialize-instance|) (note-ii-change method))
  2941.           ((eq gf |#'reinitialize-instance|) (note-ri-change method))
  2942.           ((eq gf |#'shared-initialize|) (note-si-change method))
  2943.     )
  2944.     (setf (gf-methods gf)
  2945.           (cons method
  2946.                 (if old-method
  2947.                   (progn
  2948.                     (warn (DEUTSCH "Methode ~S in ~S wird ersetzt."
  2949.                            ENGLISH "Replacing method ~S in ~S"
  2950.                            FRANCAIS "On remplace la mΘthode ~S dans ~S.")
  2951.                           old-method gf
  2952.                     )
  2953.                     (remove old-method (gf-methods gf))
  2954.                   )
  2955.                   (gf-methods gf)
  2956.     )     )     )
  2957.     (finalize-fast-gf gf)
  2958.   )
  2959.   gf
  2960. )
  2961.  
  2962. ; Entfernen einer Methode von einer generischen Funktion:
  2963. (defun std-remove-method (gf method)
  2964.   (let ((old-method (find (std-method-initfunction method) (gf-methods gf)
  2965.                           :key #'std-method-initfunction)))
  2966.     (when old-method
  2967.       (warn-if-gf-already-called gf)
  2968.       (warn (DEUTSCH "Methode ~S in ~S wird entfernt."
  2969.              ENGLISH "Removing method ~S in ~S"
  2970.              FRANCAIS "On retire la mΘthode ~S de ~S.")
  2971.             old-method gf
  2972.       )
  2973.       (cond ((eq gf |#'initialize-instance|) (note-ii-change method))
  2974.             ((eq gf |#'reinitialize-instance|) (note-ri-change method))
  2975.             ((eq gf |#'shared-initialize|) (note-si-change method))
  2976.       )
  2977.       (setf (gf-methods gf) (remove old-method (gf-methods gf)))
  2978.       (finalize-fast-gf gf)
  2979.   ) )
  2980.   gf
  2981. )
  2982.  
  2983. ; Aufsuchen einer Methode in einer generischen Funktion:
  2984. (defun std-find-method (gf qualifiers specializers &optional (errorp t))
  2985.   ; sozusagen
  2986.   ;   (find hypothetical-method (gf-methods gf) :test #'methods-agree-p)
  2987.   ; vgl. methods-agree-p
  2988.   (dolist (method (gf-methods gf))
  2989.     (when (and (equal (std-method-qualifiers method) qualifiers)
  2990.                (specializers-agree-p (std-method-parameter-specializers method)
  2991.                                      specializers
  2992.           )    )
  2993.       (return-from std-find-method method)
  2994.   ) )
  2995.   (if errorp
  2996.     (error-of-type 'error
  2997.       (DEUTSCH "~S hat keine Methode mit Bestimmern ~:S und Spezialierung ~S."
  2998.        ENGLISH "~S has no method with qualifiers ~:S and specializers ~S"
  2999.        FRANCAIS "~S n'a pas de mΘthode qualifiΘe ~:S qui est spΘcialisΘe sur ~S.")
  3000.       gf qualifiers specializers
  3001.     )
  3002.     nil
  3003. ) )
  3004.  
  3005.  
  3006. ;;; DEFMETHOD
  3007.  
  3008. (defmacro defmethod (funname &rest method-description &environment env)
  3009.   (unless (function-name-p funname)
  3010.     (error-of-type 'program-error
  3011.       (DEUTSCH "~S: Der Name einer Funktion mu▀ ein Symbol sein, nicht: ~S"
  3012.        ENGLISH "~S: the name of a function must be a symbol, not ~S"
  3013.        FRANCAIS "~S : Le nom d'une fonction doit Ωtre un symbole et non ~S")
  3014.       'defmethod funname
  3015.   ) )
  3016.   `(LET ()
  3017.      (EVAL-WHEN (COMPILE) (COMPILER::C-DEFUN ',funname))
  3018.      (DO-DEFMETHOD ',funname
  3019.        ,(analyze-method-description 'defmethod funname method-description env)
  3020.    ) )
  3021. )
  3022.  
  3023. (defun do-defmethod (funname method)
  3024.   (std-add-method
  3025.     (if (fboundp funname)
  3026.       (let ((gf (fdefinition funname)))
  3027.         (if (clos::generic-function-p gf)
  3028.           gf
  3029.           (error-of-type 'error
  3030.             (DEUTSCH "~S bezeichnet keine generische Funktion."
  3031.              ENGLISH "~S doesn't name a generic function"
  3032.              FRANCAIS "~S n'est pas ne nom d'une fonction gΘnΘrique.")
  3033.             funname
  3034.       ) ) )
  3035.       (setf (fdefinition funname)
  3036.             (let ((signature (std-method-signature method)))
  3037.               (make-fast-gf funname
  3038.                             ; GF-Signatur aus der Methoden-Signatur bestimmen:
  3039.                             (list (first signature) ; reqanz
  3040.                                   (second signature) ; optanz
  3041.                                   (third signature) ; restp
  3042.                                   '() ; keywords
  3043.                                   nil ; allowp
  3044.                             )
  3045.                             ; argorder := (0 ... reqanz-1)
  3046.                             (countup (first signature))
  3047.       )     ) )
  3048.     )
  3049.     method
  3050.   )
  3051.   method
  3052. )
  3053.  
  3054. ; n --> Liste (0 ... n-1)
  3055. (defun countup (n)
  3056.   (do* ((count n (1- count))
  3057.         (l '() (cons count l)))
  3058.        ((eql count 0) l)
  3059. ) )
  3060.  
  3061.  
  3062. ;; Fⁿr DEFGENERIC, GENERIC-FUNCTION, GENERIC-FLET, GENERIC-LABELS,
  3063. ;; WITH-ADDED-METHODS
  3064.   ; caller: Symbol
  3065.   ; funname: Funktionsname, Symbol oder (SETF symbol)
  3066.   ; lambdalist: Lambdaliste der generischen Funktion
  3067.   ; options: (option*)
  3068.   ; --> signature, argorder, method-forms, docstring
  3069. (defun analyze-defgeneric (caller funname lambdalist options env)
  3070.   (unless (function-name-p funname)
  3071.     (error-of-type 'program-error
  3072.       (DEUTSCH "~S: Der Name einer Funktion mu▀ ein Symbol sein, nicht: ~S"
  3073.        ENGLISH "~S: the name of a function must be a symbol, not ~S"
  3074.        FRANCAIS "~S : Le nom d'une fonction doit Ωtre un symbole et non ~S")
  3075.       caller funname lambdalist
  3076.   ) )
  3077.   ; Lambdaliste parsen:
  3078.   (multiple-value-bind (reqanz req-vars optanz restp keywords allowp)
  3079.       (analyze-defgeneric-lambdalist caller funname lambdalist)
  3080.     ; Optionen abarbeiten:
  3081.     (let ((method-forms '())
  3082.           (argorders nil)
  3083.           (docstrings nil))
  3084.       (dolist (option options)
  3085.         (unless (listp option)
  3086.           (error-of-type 'program-error
  3087.             (DEUTSCH "~S ~S: Das ist keine ~S-Option: ~S"
  3088.              ENGLISH "~S ~S: not a ~S option: ~S"
  3089.              FRANCAIS "~S ~S : Ceci n'est pas une option ~S: ~S")
  3090.             caller funname 'defgeneric option
  3091.         ) )
  3092.         (case (first option)
  3093.           (DECLARE
  3094.             (unless (every
  3095.                        #'(lambda (x) (and (consp x) (eq (first x) 'OPTIMIZE)))
  3096.                        (rest option)
  3097.                     )
  3098.               (warn (DEUTSCH "~S ~S: Erlaubt sind nur ~S-Deklarationen: ~S"
  3099.                      ENGLISH "~S ~S: Only ~S declarations are permitted: ~S"
  3100.                      FRANCAIS "~S ~S : Seules les dΘclarations ~S sont permises: ~S")
  3101.                     caller funname 'optimize option
  3102.             ) )
  3103.             ; Die Deklaration wird ignoriert.
  3104.             ; Der Compiler ignoriert sie sowieso.
  3105.           )
  3106.           (:ARGUMENT-PRECEDENCE-ORDER
  3107.             (when argorders
  3108.               (error-of-type 'program-error
  3109.                 (DEUTSCH "~S ~S: ~S darf nur einmal angegeben werden."
  3110.                  ENGLISH "~S ~S: ~S may only be specified once."
  3111.                  FRANCAIS "~S ~S : ~S ne peut Ωtre spΘcifiΘ qu'une seule fois.")
  3112.                 caller funname ':argument-precedence-order
  3113.             ) )
  3114.             (setq argorders option)
  3115.           )
  3116.           (:DOCUMENTATION
  3117.             (unless (and (eql (length option) 2) (stringp (second option)))
  3118.               (error-of-type 'program-error
  3119.                 (DEUTSCH "~S ~S: Nach ~S mu▀ ein String angegeben werden: ~S"
  3120.                  ENGLISH "~S ~S: A string must be specified after ~S : ~S"
  3121.                  FRANCAIS "~S ~S : Il faut une chaεne aprΦs ~S : ~S")
  3122.                 caller funname ':documentation option
  3123.             ) )
  3124.             (when docstrings
  3125.               (error-of-type 'program-error
  3126.                 (DEUTSCH "~S ~S: Es ist h÷chstens ein ~S-String erlaubt."
  3127.                  ENGLISH "~S ~S: Only one ~S string is allowed"
  3128.                  FRANCAIS "~S ~S : Il faut qu'une seule chaεne ~S.")
  3129.                 caller funname ':documentation
  3130.             ) )
  3131.             (setq docstrings (rest option))
  3132.           )
  3133.           (:METHOD-COMBINATION
  3134.             (unless (equal (rest option) '(STANDARD))
  3135.               (error-of-type 'program-error
  3136.                 (DEUTSCH "~S ~S: Als Methodenkombination ist nur ~S zugelassen: ~S"
  3137.                  ENGLISH "~S ~S: The only valid method combination is ~S : ~S"
  3138.                  FRANCAIS "~S ~S : La seule combinaison de mΘthodes valable est ~S : ~S")
  3139.                 caller funname 'standard option
  3140.             ) )
  3141.             ; Die Methodenkombination wird ignoriert.
  3142.           )
  3143.           (:GENERIC-FUNCTION-CLASS
  3144.             (unless (equal (rest option) '(STANDARD-GENERIC-FUNCTION))
  3145.               (error-of-type 'program-error
  3146.                 (DEUTSCH "~S ~S: Als Name der Klasse der generischen Funktion ist nur ~S zugelassen: ~S"
  3147.                  ENGLISH "~S ~S: The only valid generic function class name is ~S : ~S"
  3148.                  FRANCAIS "~S ~S : Le seul nom valable d'une classe de fonction gΘnΘrique est ~S : ~S")
  3149.                 caller funname 'standard-generic-function option
  3150.             ) )
  3151.             ; Die Klasse der generischen Funktion wird ignoriert.
  3152.           )
  3153.           (:METHOD-CLASS
  3154.             (unless (equal (rest option) '(STANDARD-METHOD))
  3155.               (error-of-type 'program-error
  3156.                 (DEUTSCH "~S ~S: Als Name der Klasse der Methoden ist nur ~S zugelassen: ~S"
  3157.                  ENGLISH "~S ~S: The only valid method class name is ~S : ~S"
  3158.                  FRANCAIS "~S ~S : Le seul nom valable d'une classe de mΘthodes est ~S : ~S")
  3159.                 caller funname 'standard-method option
  3160.             ) )
  3161.             ; Die Klasse der Methoden wird ignoriert.
  3162.           )
  3163.           (:METHOD
  3164.             (push (analyze-method-description caller funname (rest option) env)
  3165.                   method-forms
  3166.           ) )
  3167.           (t (error-of-type 'program-error
  3168.                (DEUTSCH "~S ~S: Falsche Syntax in ~S-Option: ~S"
  3169.                 ENGLISH "~S ~S: invalid syntax in ~S option: ~S"
  3170.                 FRANCAIS "~S ~S : Mauvaise syntaxe dans l'option ~S: ~S")
  3171.                caller funname 'defstruct option
  3172.       ) ) )  )
  3173.       ; :argument-precedence-order ⁿberprⁿfen:
  3174.       (let ((argorder
  3175.               (if argorders
  3176.                 (let ((l (mapcar #'(lambda (x)
  3177.                                      (or (position x req-vars)
  3178.                                          (error-of-type 'program-error
  3179.                                            (DEUTSCH "~S ~S: ~S ist keiner der notwendigen Parameter: ~S"
  3180.                                             ENGLISH "~S ~S: ~S is not one of the required parameters: ~S"
  3181.                                             FRANCAIS "~S ~S : ~S n'est pas parmi les noms d'arguments obligatoires: ~S")
  3182.                                            caller funname x argorders
  3183.                                    ) )   )
  3184.                                  (rest argorders)
  3185.                      ))  )
  3186.                   ; Ist (rest argorders) eine Permutation von req-vars ?
  3187.                   ; Anders ausgedrⁿckt: Ist die Abbildung
  3188.                   ;        (rest argorders)  -->  req-vars
  3189.                   ; bzw.   l --> {0, ..., reqanz-1}
  3190.                   ; bijektiv?
  3191.                   (unless (apply #'/= l) ; injektiv?
  3192.                     (error-of-type 'program-error
  3193.                       (DEUTSCH "~S ~S: eine Variable taucht in ~S doppelt auf."
  3194.                        ENGLISH "~S ~S: some variable occurs twice in ~S"
  3195.                        FRANCAIS "~S ~S : une variable apparaεt plusieurs fois dans ~S.")
  3196.                       caller funname argorders
  3197.                   ) )
  3198.                   (unless (eql (length l) reqanz) ; surjektiv?
  3199.                     (error-of-type 'program-error
  3200.                       (DEUTSCH "~S ~S: ~S enthΣlt nicht alle notwendigen Parameter."
  3201.                        ENGLISH "~S ~S: ~S is missing some required parameter"
  3202.                        FRANCAIS "~S ~S : ~S ne contient pas tous les noms d'arguments obligatoires.")
  3203.                       caller funname argorders
  3204.                   ) )
  3205.                   l
  3206.                 )
  3207.                 (countup reqanz)
  3208.            )) )
  3209.         (values ; Signatur
  3210.                 `(,reqanz ,optanz ,restp ,keywords ,allowp)
  3211.                 ; argorder
  3212.                 argorder
  3213.                 ; Liste der Methoden-Formen
  3214.                 (nreverse method-forms)
  3215.                 ; docstring oder nil
  3216.                 (car docstrings)
  3217.         )
  3218. ) ) ) )
  3219.  
  3220. ; Lambdaliste parsen:
  3221. ; lambdalist --> reqanz, req-vars, optanz, restp, keywords, allowp
  3222. (defun analyze-defgeneric-lambdalist (caller funname lambdalist)
  3223.   (let ((req-vars '())
  3224.         (optanz 0)
  3225.         (restp nil)
  3226.         (keyp nil)
  3227.         (keywords '())
  3228.         (allowp nil))
  3229.     (when (some #'(lambda (item) (and (consp item) (cdr item))) lambdalist)
  3230.       (error-of-type 'program-error
  3231.         (DEUTSCH "~S ~S: In der Lambda-Liste einer generischen Funktion sind keine Initialisierungen erlaubt: ~S"
  3232.          ENGLISH "~S ~S: No initializations are allowed in a generic function lambda-list: ~S"
  3233.          FRANCAIS "~S ~S : Des initialisations ne sont pas permises dans la liste lambda d'une fonction gΘnΘrique: ~S")
  3234.         caller funname lambdalist
  3235.     ) )
  3236.     (flet ((check-varname (var)
  3237.              (unless (symbolp var)
  3238.                (error-of-type 'program-error
  3239.                  (DEUTSCH "~S ~S: Variablenname mu▀ ein Symbol sein, nicht ~S"
  3240.                   ENGLISH "~S ~S: variable name ~S should be a symbol"
  3241.                   FRANCAIS "~S ~S : le nom de variable ~S devrait Ωtre un symbole.")
  3242.                  caller funname var
  3243.              ) )
  3244.              (when (member var req-vars :test #'eq)
  3245.                (error-of-type 'program-error
  3246.                  (DEUTSCH "~S ~S: Variablenname ~S darf nicht mehrfach auftreten."
  3247.                   ENGLISH "~S ~S: duplicate variable name ~S"
  3248.                   FRANCAIS "~S ~S : le nom de variable ~S apparaεt plusieurs fois.")
  3249.                  caller funname var
  3250.              ) )
  3251.              var
  3252.           ))
  3253.       (loop
  3254.         (when (or (atom lambdalist) (lambda-list-keyword-p (first lambdalist)))
  3255.           (return)
  3256.         )
  3257.         (push (check-varname (pop lambdalist)) req-vars)
  3258.       )
  3259.       (when (and (consp lambdalist) (eq (first lambdalist) '&optional))
  3260.         (pop lambdalist)
  3261.         (loop
  3262.           (when (or (atom lambdalist) (lambda-list-keyword-p (first lambdalist)))
  3263.             (return)
  3264.           )
  3265.           (let ((item (pop lambdalist)))
  3266.             (check-varname (if (consp item) (first item) item))
  3267.             (incf optanz)
  3268.       ) ) )
  3269.       (when (and (consp lambdalist) (eq (first lambdalist) '&rest)
  3270.                  (consp (rest lambdalist))
  3271.             )
  3272.         (pop lambdalist)
  3273.         (check-varname (pop lambdalist))
  3274.         (setq restp t)
  3275.       )
  3276.       (when (and (consp lambdalist) (eq (first lambdalist) '&key))
  3277.         (pop lambdalist)
  3278.         (setq restp t) ; &key impliziert &rest
  3279.         (loop
  3280.           (when (or (atom lambdalist) (lambda-list-keyword-p (first lambdalist)))
  3281.             (return)
  3282.           )
  3283.           (let ((item (pop lambdalist)))
  3284.             (when (consp item) (setq item (first item)))
  3285.             (check-varname (if (consp item) (second item) item))
  3286.             (push (if (consp item)
  3287.                     (first item)
  3288.                     (intern (symbol-name item) *keyword-package*)
  3289.                   )
  3290.                   keywords
  3291.         ) ) )
  3292.         (when (and (consp lambdalist) (eq (first lambdalist) '&allow-other-keys))
  3293.           (pop lambdalist)
  3294.           (setq allowp t)
  3295.       ) )
  3296.     )
  3297.     (when lambdalist
  3298.       (error-of-type 'program-error
  3299.         (DEUTSCH "~S ~S: Lambda-Liste enthΣlt UnzulΣssiges: ~S"
  3300.          ENGLISH "~S ~S: invalid lambda list portion: ~S"
  3301.          FRANCAIS "~S ~S : liste lambda partiellement invalide: ~S")
  3302.         caller funname lambdalist
  3303.     ) )
  3304.     (values (length req-vars) (nreverse req-vars) optanz
  3305.             (or restp keyp) keywords allowp
  3306. ) ) )
  3307.  
  3308. ; Lambdaliste in Aufrufkonvention umrechnen:
  3309. (defun defgeneric-lambdalist-callinfo (caller funname lambdalist)
  3310.   (multiple-value-bind (reqanz req-vars optanz restp keywords allowp)
  3311.       (analyze-defgeneric-lambdalist caller funname lambdalist)
  3312.     (declare (ignore req-vars))
  3313.     (callinfo reqanz optanz restp keywords allowp)
  3314. ) )
  3315.  
  3316.  
  3317. ;;; DEFGENERIC
  3318.  
  3319. (defmacro defgeneric (funname lambda-list &rest options &environment env)
  3320.   (multiple-value-bind (signature argorder method-forms docstring)
  3321.       (analyze-defgeneric 'defgeneric funname lambda-list options env)
  3322.     `(LET ()
  3323.        (EVAL-WHEN (COMPILE) (COMPILER::C-DEFUN ',funname))
  3324.        ; NB: Kein (SYSTEM::REMOVE-OLD-DEFINITIONS ',funname)
  3325.        ,@(if docstring
  3326.            (let ((symbolform
  3327.                    (if (atom funname)
  3328.                      `',funname
  3329.                      `(LOAD-TIME-VALUE (SYSTEM::GET-SETF-SYMBOL ',(second funname)))
  3330.                 )) )
  3331.              `((SYSTEM::%SET-DOCUMENTATION ,symbolform 'FUNCTION ',docstring))
  3332.          ) )
  3333.        (DO-DEFGENERIC ',funname ',signature ',argorder ,@method-forms)
  3334.      )
  3335. ) )
  3336.  
  3337. (defun make-generic-function (funname signature argorder &rest methods)
  3338.   (let ((gf (make-fast-gf funname signature argorder)))
  3339.     (dolist (method methods) (std-add-method gf method))
  3340.     (finalize-fast-gf gf)
  3341.     gf
  3342. ) )
  3343.  
  3344. (defun do-defgeneric (funname signature argorder &rest methods)
  3345.   (if (fboundp funname)
  3346.     (let ((gf (fdefinition funname)))
  3347.       (if (clos::generic-function-p gf)
  3348.         ; Umdefinition einer generischen Funktion
  3349.         (progn
  3350.           (warn-if-gf-already-called gf)
  3351.           (unless (null (gf-methods gf))
  3352.             (warn (DEUTSCH "Alle Methoden von ~S werden entfernt."
  3353.                    ENGLISH "Removing all methods of ~S"
  3354.                    FRANCAIS "On enlΦve toutes les mΘthodes de ~S.")
  3355.                   gf
  3356.             )
  3357.             (setf (gf-methods gf) nil)
  3358.           )
  3359.           (unless (and (equal signature (gf-signature gf))
  3360.                        (equal argorder (gf-argorder gf))
  3361.                   )
  3362.             (warn (DEUTSCH "Das Parameter-Profil von ~S wird modifiziert."
  3363.                    ENGLISH "Modifying the parameter profile of ~S"
  3364.                    FRANCAIS "On change le nombre / l'ordre des arguments de ~S.")
  3365.                   gf
  3366.             )
  3367.             (setf (gf-signature gf) signature)
  3368.             (setf (gf-argorder gf) argorder)
  3369.           )
  3370.           (dolist (method methods) (std-add-method gf method))
  3371.           (finalize-fast-gf gf)
  3372.           gf
  3373.         )
  3374.         (error-of-type 'error ; 'program-error ??
  3375.           (DEUTSCH "~S bezeichnet keine generische Funktion."
  3376.            ENGLISH "~S doesn't name a generic function"
  3377.            FRANCAIS "~S n'est pas le nom d'une fonction gΘnΘrique.")
  3378.           funname
  3379.     ) ) )
  3380.     (setf (fdefinition funname)
  3381.           (apply #'make-generic-function funname signature argorder methods)
  3382. ) ) )
  3383.  
  3384.  
  3385. #|
  3386. ;; Fⁿr GENERIC-FLET, GENERIC-LABELS
  3387.  
  3388. ; Wie make-generic-function, nur da▀ der Dispatch-Code gleich installiert wird.
  3389. (defun make-generic-function-now (funname signature argorder &rest methods)
  3390.   (let ((gf (make-fast-gf funname signature argorder)))
  3391.     (dolist (method methods) (std-add-method gf method))
  3392.     (install-dispatch gf)
  3393.     gf
  3394. ) )
  3395. |#
  3396.  
  3397.  
  3398. ;; Fⁿr GENERIC-FUNCTION, GENERIC-FLET, GENERIC-LABELS
  3399.  
  3400. (defun make-generic-function-form (caller funname lambda-list options env)
  3401.   (multiple-value-bind (signature argorder method-forms docstring)
  3402.       (analyze-defgeneric caller funname lambda-list options env)
  3403.     (declare (ignore docstring))
  3404.     `(MAKE-GENERIC-FUNCTION ',funname ',signature ',argorder ,@method-forms)
  3405. ) )
  3406.  
  3407.  
  3408. ;;; GENERIC-FUNCTION
  3409.  
  3410. (defmacro generic-function (lambda-list &rest options &environment env)
  3411.   (make-generic-function-form 'generic-function 'LAMBDA lambda-list options env)
  3412. )
  3413.  
  3414.  
  3415. ;; Fⁿr GENERIC-FLET, GENERIC-LABELS
  3416. (defun analyze-generic-fundefs (caller fundefs env)
  3417.   (let ((names '())
  3418.         (funforms '()))
  3419.     (dolist (fundef fundefs)
  3420.       (unless (and (consp fundef) (consp (cdr fundef)))
  3421.         (error-of-type 'program-error
  3422.           (DEUTSCH "~S: ~S ist keine Spezifikation einer generischen Funktion."
  3423.            ENGLISH "~S: ~S is not a generic function specification"
  3424.            FRANCAIS "~S: ~S n'est pas une spΘcification de fonction gΘnΘrique.")
  3425.           caller fundef
  3426.       ) )
  3427.       (push (first fundef) names)
  3428.       (push (make-generic-function-form caller (first fundef) (second fundef) (cddr fundef) env) funforms)
  3429.     )
  3430.     (values (nreverse names) (nreverse funforms))
  3431. ) )
  3432.  
  3433.  
  3434. ;;; GENERIC-FLET
  3435.  
  3436. (defmacro generic-flet (fundefs &body body &environment env)
  3437.   (multiple-value-bind (funnames funforms)
  3438.       (analyze-generic-fundefs 'generic-flet fundefs env)
  3439.     (let ((varnames (n-gensyms (length funnames))))
  3440.       `(LET ,(mapcar #'list varnames funforms)
  3441.          (FLET ,(mapcar #'(lambda (varname funname)
  3442.                             `(,funname (&rest args) (apply ,varname args))
  3443.                           )
  3444.                         varnames funnames
  3445.                 )
  3446.            ,@body
  3447.        ) )
  3448. ) ) )
  3449.  
  3450.  
  3451. ;;; GENERIC-LABELS
  3452.  
  3453. (defmacro generic-labels (fundefs &body body &environment env)
  3454.   (multiple-value-bind (funnames funforms)
  3455.       (analyze-generic-fundefs 'generic-labels fundefs env)
  3456.     (let ((varnames (n-gensyms (length funnames))))
  3457.       `(LET ,varnames
  3458.          (FLET ,(mapcar #'(lambda (varname funname)
  3459.                             `(,funname (&rest args) (apply ,varname args))
  3460.                           )
  3461.                         varnames funnames
  3462.                 )
  3463.            ,@(mapcar #'(lambda (varname funform) `(SETQ ,varname ,funform))
  3464.                      varnames funforms
  3465.              )
  3466.            ,@body
  3467.        ) )
  3468. ) ) )
  3469.  
  3470.  
  3471. ;;; WITH-ADDED-METHODS
  3472. ; ist vermurkst und wird deshalb nicht implementiert.
  3473.  
  3474.  
  3475. ;;; Verschiedene generische Funktionen, die wir bis jetzt hinausgez÷gert haben:
  3476.  
  3477. (defgeneric class-name (class)
  3478.   (:method ((class class))
  3479.     (class-classname class)
  3480. ) )
  3481.  
  3482. (defgeneric (setf class-name) (new-value class)
  3483.   (:method (new-value (class class))
  3484.     (unless (symbolp new-value)
  3485.       (error-of-type 'type-error
  3486.         :datum new-value :expected-type 'symbol
  3487.         (DEUTSCH "~S: Der Name einer Klasse mu▀ ein Symbol sein, nicht ~S"
  3488.          ENGLISH "~S: The name of a class must be a symbol, not ~S"
  3489.          FRANCAIS "~S : Le nom d'une classe doit Ωtre un symbole et non ~S.")
  3490.         '(setf class-name) new-value
  3491.     ) )
  3492.     (when (built-in-class-p class)
  3493.       (error-of-type 'error
  3494.         (DEUTSCH "~S: Der Name der Built-In-Klasse ~S kann nicht verΣndert werden."
  3495.          ENGLISH "~S: The name of the built-in class ~S cannot be modified"
  3496.          FRANCAIS "~S : Le nom de la classe prΘdΘfinie ~S ne peut pas Ωtre changΘe.")
  3497.         '(setf class-name) class
  3498.     ) )
  3499.     (setf (class-classname class) new-value)
  3500. ) )
  3501.  
  3502. (defgeneric no-applicable-method (gf &rest args)
  3503.   (:method ((gf t) &rest args)
  3504.     (error-of-type 'error
  3505.       (DEUTSCH "~S: Beim Aufruf von ~S mit Argumenten ~S ist keine Methode anwendbar."
  3506.        ENGLISH "~S: When calling ~S with arguments ~S, no method is applicable."
  3507.        FRANCAIS "~S : └ l'appel de ~S avec les arguments ~S, aucune mΘthode ne s'applique.")
  3508.       'no-applicable-method gf args
  3509. ) ) )
  3510.  
  3511. (defgeneric no-primary-method (gf &rest args)
  3512.   (:method ((gf t) &rest args)
  3513.     (error-of-type 'error
  3514.       (DEUTSCH "~S: Beim Aufruf von ~S mit Argumenten ~S ist keine primΣre Methode anwendbar."
  3515.        ENGLISH "~S: When calling ~S with arguments ~S, no primary method is applicable."
  3516.        FRANCAIS "~S : └ l'appel de ~S avec les arguments ~S, aucune mΘthode primaire ne s'applique.")
  3517.       'no-primary-method gf args
  3518. ) ) )
  3519.  
  3520. (defun %no-next-method (method &rest args)
  3521.   (apply #'no-next-method (std-method-gf method) method args)
  3522. )
  3523. (defgeneric no-next-method (gf method &rest args)
  3524.   (:method ((gf standard-generic-function) (method standard-method) &rest args)
  3525.     (error-of-type 'error
  3526.       (DEUTSCH "~S: Beim Aufruf von ~S mit Argumenten ~S gibt es nach ~S keine weitere Methode, und ~S wurde aufgerufen."
  3527.        ENGLISH "~S: When calling ~S with arguments ~S, there is no next method after ~S, and ~S was called."
  3528.        FRANCAIS "~S : └ l'appel de ~S avec les arguments ~S, il n'y a plus de mΘthode aprΦs ~S, et ~S a ΘtΘ appelΘ.")
  3529.       'no-next-method gf args method '(call-next-method)
  3530. ) ) )
  3531.  
  3532. (defgeneric find-method (gf qualifiers specializers &optional errorp)
  3533.   (:method ((gf standard-generic-function) qualifiers specializers &optional (errorp t))
  3534.      (std-find-method gf qualifiers specializers errorp)
  3535. ) )
  3536.  
  3537. (defgeneric add-method (gf method)
  3538.   (:method ((gf standard-generic-function) (method standard-method))
  3539.     (std-add-method gf method)
  3540. ) )
  3541.  
  3542. (defgeneric remove-method (gf method)
  3543.   (:method ((gf standard-generic-function) (method standard-method))
  3544.     (std-remove-method gf method)
  3545. ) )
  3546.  
  3547. (defun compute-applicable-methods (gf args)
  3548.   (let ((reqanz (first (gf-signature gf)))
  3549.         (methods (gf-methods gf)))
  3550.     (if (>= (length args) reqanz)
  3551.       (let ((req-args (subseq args 0 reqanz)))
  3552.         ; 1. Select the applicable methods:
  3553.         (setq methods
  3554.           (remove-if-not
  3555.             #'(lambda (method) (method-applicable-p method req-args))
  3556.             methods
  3557.         ) )
  3558.         ; 2. Sort the applicable methods by precedence order:
  3559.         (sort-applicable-methods methods req-args (gf-argorder gf))
  3560.       )
  3561.       nil ; lieber kein Error
  3562. ) ) )
  3563.  
  3564. (defgeneric method-qualifiers (method)
  3565.   (:method ((method standard-method))
  3566.     (std-method-qualifiers method)
  3567. ) )
  3568.  
  3569. (defgeneric function-keywords (method)
  3570.   (:method ((method standard-method))
  3571.     (values-list (cddddr (std-method-signature method)))
  3572. ) )
  3573.  
  3574. (defgeneric slot-missing (class instance slot-name operation &optional new-value)
  3575.   (:method ((class t) instance slot-name operation &optional new-value)
  3576.     (declare (ignore instance new-value))
  3577.     (error-of-type 'error
  3578.       (DEUTSCH "~S: Die Klasse ~S hat keinen Slot mit Namen ~S."
  3579.        ENGLISH "~S: The class ~S has no slot named ~S"
  3580.        FRANCAIS "~S : La classe ~S n'a pas de composant de nom ~S.")
  3581.       operation class slot-name
  3582. ) ) )
  3583.  
  3584. (defgeneric slot-unbound (class instance slot-name)
  3585.   (:method ((class t) instance slot-name)
  3586.     (declare (ignore class))
  3587.     (error-of-type 'error
  3588.       (DEUTSCH "~S: Der Slot ~S von ~S hat keinen Wert."
  3589.        ENGLISH "~S: The slot ~S of ~S has no value"
  3590.        FRANCAIS "~S : Le composant ~S de ~S n'a pas de valeur.")
  3591.       'slot-value slot-name instance
  3592. ) ) )
  3593.  
  3594. (defgeneric print-object (object stream)
  3595.   (:method ((object standard-object) stream)
  3596.     (print-unreadable-object (object stream :type t :identity t))
  3597. ) )
  3598.  
  3599. (defgeneric describe-object (object stream)
  3600.   (:method ((object standard-object) s)
  3601.     (let ((slotnames (mapcar #'slotdef-name (class-slots (class-of object)))))
  3602.       (if slotnames
  3603.         (let* ((slotstrings (mapcar #'write-to-string slotnames))
  3604.                (tabpos (+ 4 (reduce #'max (mapcar #'length slotstrings)))))
  3605.           (format s (DEUTSCH "~%Slots:"
  3606.                      ENGLISH "~%Slots:"
  3607.                      FRANCAIS "~%Composants:")
  3608.           )
  3609.           (mapc #'(lambda (slotname slotstring)
  3610.                     (format s "~%  ~A~VT" slotstring tabpos)
  3611.                     (if (slot-boundp object slotname)
  3612.                       (format s "=  ~S" (slot-value object slotname))
  3613.                       (format s (DEUTSCH "ohne Wert"
  3614.                                  ENGLISH "unbound"
  3615.                                  FRANCAIS "aucune valeur")
  3616.                   ) ) )
  3617.                 slotnames slotstrings
  3618.         ) )
  3619.         (format s (DEUTSCH "~%Keine Slots."
  3620.                    ENGLISH "~%No slots."
  3621.                    FRANCAIS "~%Aucun composant.")
  3622.   ) ) ) )
  3623. )
  3624.  
  3625.  
  3626. ;; 28.1.9. Object creation and initialization
  3627.  
  3628. ; Grausamer Hack (28.1.9.2.):
  3629. ; MAKE-INSTANCE mu▀ ⁿber die Methoden von INITIALIZE-INSTANCE und
  3630. ; SHARED-INITIALIZE Bescheid wissen.
  3631. ; REINITIALIZE-INSTANCE mu▀ ⁿber die Methoden von REINITIALIZE-INSTANCE und
  3632. ; SHARED-INITIALIZE Bescheid wissen.
  3633.  
  3634. (defparameter *make-instance-table* (make-hash-table :test #'eq))
  3635.   ; Hashtabelle, die einer Klasse zuordnet ein List* aus
  3636.   ; - einer Liste der zulΣssigen Keyword-Argumente,
  3637.   ; - der effektiven Methode von initialize-instance,
  3638.   ; - der effektiven Methode von shared-initialize.
  3639.  
  3640. (defparameter *reinitialize-instance-table* (make-hash-table :test #'eq))
  3641.   ; Hashtabelle, die einer Klasse zuordnet ein Cons aus
  3642.   ; - einer Liste der zulΣssigen Keyword-Argumente,
  3643.   ; - der effektiven Methode von shared-initialize.
  3644.  
  3645. (defun note-i-change (specializer table)
  3646.   (maphash #'(lambda (class value) (declare (ignore value))
  3647.                (when (subclassp class specializer)
  3648.                  (remhash class table)
  3649.              ) )
  3650.            table
  3651. ) )
  3652.  
  3653. (defun note-ii-change (method)
  3654.   (let ((specializer (first (std-method-parameter-specializers method))))
  3655.     ; EQL-Methoden auf INITIALIZE-INSTANCE sind eh wertlos
  3656.     (unless (consp specializer)
  3657.       ; Entferne die EintrΣge von *make-instance-table*, fⁿr welche die
  3658.       ; besagte Methode anwendbar wΣre:
  3659.       (note-i-change specializer *make-instance-table*)
  3660. ) ) )
  3661.  
  3662. (defun note-ri-change (method)
  3663.   (let ((specializer (first (std-method-parameter-specializers method))))
  3664.     ; EQL-Methoden auf REINITIALIZE-INSTANCE sind im wesentlichen wertlos
  3665.     (unless (consp specializer)
  3666.       ; Entferne die EintrΣge von *reinitialize-instance-table*, fⁿr welche die
  3667.       ; besagte Methode anwendbar wΣre:
  3668.       (note-i-change specializer *reinitialize-instance-table*)
  3669. ) ) )
  3670.  
  3671. (defun note-si-change (method)
  3672.   (let* ((specializers (std-method-parameter-specializers method))
  3673.          (specializer1 (first specializers))
  3674.          (specializer2 (second specializers)))
  3675.     ; EQL-Methoden auf SHARED-INITIALIZE sind im wesentlichen wertlos
  3676.     (unless (consp specializer1)
  3677.       ; Als zweites Argument wird von INITIALIZE-INSTANCE immer nur T ⁿbergeben.
  3678.       (when (typep 'T specializer2)
  3679.         ; Entferne die EintrΣge von *make-instance-table*, fⁿr welche die
  3680.         ; besagte Methode anwendbar wΣre:
  3681.         (note-i-change specializer1 *make-instance-table*)
  3682.       )
  3683.       ; Als zweites Argument wird von REINITIALIZE-INSTANCE nur NIL ⁿbergeben.
  3684.       (when (typep 'NIL specializer2)
  3685.         ; Entferne die EintrΣge von *reinitialize-instance-table*, fⁿr welche die
  3686.         ; besagte Methode anwendbar wΣre:
  3687.         (note-i-change specializer1 *reinitialize-instance-table*)
  3688.       )
  3689. ) ) )
  3690.  
  3691. ; Aus einer Liste von anwendbaren Methoden alle Keywords sammeln:
  3692. (defun valid-initarg-keywords (class methods)
  3693.   (let ((signatures (mapcar #'std-method-signature methods)))
  3694.     ; "A method that has &rest but not &key does not affect the set of
  3695.     ;  acceptable keyword srguments."
  3696.     (setq signatures (delete-if-not #'fourth signatures))
  3697.     ; "The keyword name of each keyword parameter specified in the method's
  3698.     ;  lambda-list becomes an initialization argument for all classes for
  3699.     ;  which the method is applicable."
  3700.     (remove-duplicates
  3701.       (append (class-valid-initargs class) (mapcap #'fifth signatures))
  3702.       :from-end t
  3703. ) ) )
  3704.  
  3705. ; NB: Beim Berechnen einer effektiven Methode kommt es auf die restlichen
  3706. ; Argumente nicht an.
  3707. ; Beim ersten INITIALIZE-INSTANCE- oder MAKE-INSTANCE-Aufruf einer jeden Klasse
  3708. ; merkt man sich die ben÷tigte Information in *make-instance-table*.
  3709.  
  3710. ; Bei MAKE-INSTANCE sind als Keys gⁿltig:
  3711. ; - die Initargs, die zur Initialisierung von Slots benutzt werden,
  3712. ; - die Keywords von Methoden von SHARED-INITIALIZE,
  3713. ; - die Keywords von Methoden von INITIALIZE-INSTANCE.
  3714. (defun valid-make-instance-keywords (class)
  3715.   (valid-initarg-keywords
  3716.     class
  3717.     (append
  3718.       ; Liste aller anwendbaren Methoden von SHARED-INITIALIZE
  3719.       (remove-if-not
  3720.         #'(lambda (method)
  3721.             (let* ((specializers (std-method-parameter-specializers method))
  3722.                    (specializer1 (first specializers))
  3723.                    (specializer2 (second specializers)))
  3724.               (and (atom specializer1) (subclassp class specializer1)
  3725.                    (typep 'T specializer2)
  3726.           ) ) )
  3727.         (gf-methods |#'shared-initialize|)
  3728.       )
  3729.       ; Liste aller anwendbaren Methoden von INITIALIZE-INSTANCE
  3730.       (remove-if-not
  3731.         #'(lambda (method)
  3732.             (let ((specializer (first (std-method-parameter-specializers method))))
  3733.               (and (atom specializer) (subclassp class specializer))
  3734.           ) )
  3735.         (gf-methods |#'initialize-instance|)
  3736.       )
  3737. ) ) )
  3738. (defun make-instance-table-entry2 (instance)
  3739.   (cons (compute-effective-method |#'initialize-instance| instance)
  3740.         (compute-effective-method |#'shared-initialize| instance 'T)
  3741. ) )
  3742.  
  3743. ; 28.1.9.5., 28.1.9.4.
  3744. (defgeneric shared-initialize (instance slot-names &rest initargs))
  3745. (setq |#'shared-initialize| #'shared-initialize)
  3746. #|
  3747. (defmethod shared-initialize ((instance standard-object) slot-names &rest initargs &key &allow-other-keys)
  3748.   (dolist (slot (class-slots (class-of instance)))
  3749.     (let ((slotname (slotdef-name slot)))
  3750.       (multiple-value-bind (init-key init-value foundp)
  3751.           (get-properties initargs (slotdef-initargs slot))
  3752.         (declare (ignore init-key))
  3753.         (if foundp
  3754.           (setf (slot-value instance slotname) init-value)
  3755.           (unless (slot-boundp instance slotname)
  3756.             (let ((init (slotdef-initer slot)))
  3757.               (when init
  3758.                 (when (or (eq slot-names 'T) (member slotname slot-names :test #'eq))
  3759.                   (setf (slot-value instance slotname)
  3760.                         (if (car init) (funcall (car init)) (cdr init))
  3761.   ) ) ) ) ) ) ) ) )
  3762.   instance
  3763. )
  3764. |#
  3765. ; die Haupt-Arbeit erledigt ein SUBR:
  3766. (do-defmethod 'shared-initialize
  3767.   (make-standard-method
  3768.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3769.                       (cons #'clos::%shared-initialize '(T))
  3770.                     )
  3771.     :wants-next-method-p nil
  3772.     :parameter-specializers (list (find-class 'standard-object) (find-class 't))
  3773.     :qualifiers '()
  3774.     :signature '(2 0 t t () t)
  3775. ) )
  3776. (do-defmethod 'shared-initialize
  3777.   (make-standard-method
  3778.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3779.                       (cons #'clos::%shared-initialize '(T))
  3780.                     )
  3781.     :wants-next-method-p nil
  3782.     :parameter-specializers (list (find-class 'structure-object) (find-class 't))
  3783.     :qualifiers '()
  3784.     :signature '(2 0 t t () t)
  3785. ) )
  3786.  
  3787. ; 28.1.12.
  3788. (defgeneric reinitialize-instance (instance &rest initargs))
  3789. (setq |#'reinitialize-instance| #'reinitialize-instance)
  3790. #|
  3791. (defmethod reinitialize-instance ((instance standard-object) &rest initargs &key &allow-other-keys)
  3792.   (apply #'shared-initialize instance 'NIL initargs)
  3793. )
  3794. |#
  3795. #|
  3796. ; optimiert:
  3797. (defmethod reinitialize-instance ((instance standard-object) &rest initargs &key &allow-other-keys)
  3798.   (let ((h (gethash (class-of instance) *reinitialize-instance-table*)))
  3799.     (if h
  3800.       (progn
  3801.         ; 28.1.9.2. validity of initialization arguments
  3802.         (let ((valid-keywords (car h)))
  3803.           (sys::keyword-test initargs valid-keywords)
  3804.         )
  3805.         (if (not (eq (cdr h) #'clos::%shared-initialize))
  3806.           ; effektive Methode von shared-initialize anwenden:
  3807.           (apply (cdr h) instance 'NIL initargs)
  3808.           ; clos::%shared-initialize mit slot-names=NIL lΣ▀t sich vereinfachen:
  3809.           (progn
  3810.             (dolist (slot (class-slots (class-of instance)))
  3811.               (let ((slotname (slotdef-name slot)))
  3812.                 (multiple-value-bind (init-key init-value foundp)
  3813.                     (get-properties initargs (slotdef-initargs slot))
  3814.                   (declare (ignore init-key))
  3815.                   (if foundp
  3816.                     (setf (slot-value instance slotname) init-value)
  3817.             ) ) ) )
  3818.             instance
  3819.       ) ) )
  3820.       (apply #'initial-reinitialize-instance instance initargs)
  3821. ) ) )
  3822. |#
  3823. ; die Haupt-Arbeit erledigt ein SUBR:
  3824. (do-defmethod 'reinitialize-instance
  3825.   (make-standard-method
  3826.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3827.                       (cons #'clos::%reinitialize-instance '(T))
  3828.                     )
  3829.     :wants-next-method-p nil
  3830.     :parameter-specializers (list (find-class 'standard-object))
  3831.     :qualifiers '()
  3832.     :signature '(1 0 t t () t)
  3833. ) )
  3834. (do-defmethod 'reinitialize-instance
  3835.   (make-standard-method
  3836.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3837.                       (cons #'clos::%reinitialize-instance '(T))
  3838.                     )
  3839.     :wants-next-method-p nil
  3840.     :parameter-specializers (list (find-class 'structure-object))
  3841.     :qualifiers '()
  3842.     :signature '(1 0 t t () t)
  3843. ) )
  3844. ; Beim ersten REINITIALIZE-INSTANCE-Aufruf einer jeden Klasse merkt man sich die
  3845. ; ben÷tigte Information in *reinitialize-instance-table*.
  3846. (defun initial-reinitialize-instance (instance &rest initargs)
  3847.   (let* ((class (class-of instance))
  3848.          (valid-keywords
  3849.            (valid-initarg-keywords
  3850.              class
  3851.              ; Liste aller anwendbaren Methoden von SHARED-INITIALIZE
  3852.              (remove-if-not
  3853.                #'(lambda (method)
  3854.                    (let* ((specializers (std-method-parameter-specializers method))
  3855.                           (specializer1 (first specializers))
  3856.                           (specializer2 (second specializers)))
  3857.                      (and (atom specializer1) (subclassp class specializer1)
  3858.                           (typep 'NIL specializer2)
  3859.                  ) ) )
  3860.                (gf-methods |#'shared-initialize|)
  3861.         )) ) )
  3862.     ; 28.1.9.2. validity of initialization arguments
  3863.     (sys::keyword-test initargs valid-keywords)
  3864.     (let ((si-ef (compute-effective-method |#'shared-initialize| instance 'NIL)))
  3865.       (setf (gethash class *reinitialize-instance-table*) (cons valid-keywords si-ef))
  3866.       (apply si-ef instance 'NIL initargs)
  3867. ) ) )
  3868.  
  3869. ; 28.1.9.6.
  3870. (defgeneric initialize-instance (instance &rest initargs))
  3871. (setq |#'initialize-instance| #'initialize-instance)
  3872. #|
  3873. (defmethod initialize-instance ((instance standard-object) &rest initargs &key &allow-other-keys)
  3874.   (apply #'shared-initialize instance 'T initargs)
  3875. )
  3876. |#
  3877. #|
  3878. ; optimiert:
  3879. (defmethod initialize-instance ((instance standard-object) &rest initargs &key &allow-other-keys)
  3880.   (let ((h (gethash class *make-instance-table*)))
  3881.     (if h
  3882.       (if (not (eq (cddr h) #'clos::%shared-initialize))
  3883.         ; effektive Methode von shared-initialize anwenden:
  3884.         (apply (cddr h) instance 'T initargs)
  3885.         ; clos::%shared-initialize mit slot-names=T lΣ▀t sich vereinfachen:
  3886.         (progn
  3887.           (dolist (slot (class-slots (class-of instance)))
  3888.             (let ((slotname (slotdef-name slot)))
  3889.               (multiple-value-bind (init-key init-value foundp)
  3890.                   (get-properties initargs (slotdef-initargs slot))
  3891.                 (declare (ignore init-key))
  3892.                 (if foundp
  3893.                   (setf (slot-value instance slotname) init-value)
  3894.                   (unless (slot-boundp instance slotname)
  3895.                     (let ((init (slotdef-initer slot)))
  3896.                       (when init
  3897.                         (setf (slot-value instance slotname)
  3898.                               (if (car init) (funcall (car init)) (cdr init))
  3899.           ) ) ) ) ) ) ) )
  3900.           instance
  3901.       ) )
  3902.       (apply #'initial-initialize-instance instance initargs)
  3903. ) ) )
  3904. |#
  3905. ; die Haupt-Arbeit erledigt ein SUBR:
  3906. (do-defmethod 'initialize-instance
  3907.   (make-standard-method
  3908.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3909.                       (cons #'clos::%initialize-instance '(T))
  3910.                     )
  3911.     :wants-next-method-p nil
  3912.     :parameter-specializers (list (find-class 'standard-object))
  3913.     :qualifiers '()
  3914.     :signature '(1 0 t t () t)
  3915. ) )
  3916. (do-defmethod 'initialize-instance
  3917.   (make-standard-method
  3918.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3919.                       (cons #'clos::%initialize-instance '(T))
  3920.                     )
  3921.     :wants-next-method-p nil
  3922.     :parameter-specializers (list (find-class 'structure-object))
  3923.     :qualifiers '()
  3924.     :signature '(1 0 t t () t)
  3925. ) )
  3926. (defun initial-initialize-instance (instance &rest initargs)
  3927.   (let* ((class (class-of instance))
  3928.          (valid-keywords (valid-make-instance-keywords class))
  3929.          (efs (make-instance-table-entry2 instance)))
  3930.     (setf (gethash class *make-instance-table*) (cons valid-keywords efs))
  3931.     ; effektive Methode von SHARED-INITIALIZE anwenden:
  3932.     (apply (cdr efs) instance 'T initargs)
  3933. ) )
  3934.  
  3935. ; allocate-instance is not exported and not terribly optimized since
  3936. ; CLtL2 doesn't document it. User-defined methods on it are not supported.
  3937. #|
  3938. (defgeneric allocate-instance (class)
  3939.   (:method ((class standard-class))
  3940.     (allocate-std-instance class (class-instance-size class))
  3941.   )
  3942.   (:method ((class structure-class))
  3943.     (sys::%make-structure (class-names class) (class-instance-size class) :initial-element unbound)
  3944. ) )
  3945. |#
  3946. #|
  3947. (defun %allocate-instance (class)
  3948.   ; Quick and dirty dispatch among <standard-class> and <structure-class>.
  3949.   ; (class-shared-slots class) is a simple-vector, (class-names class) a cons.
  3950.   (if (atom (class-shared-slots class))
  3951.     (allocate-std-instance class (class-instance-size class))
  3952.     (sys::%make-structure (class-names class) (class-instance-size class) :initial-element unbound)
  3953. ) )
  3954. |#
  3955. ; see record.d
  3956.  
  3957. ; 28.1.9.7.
  3958. (defgeneric make-instance (class &rest initargs)
  3959.   (:method ((class symbol) &rest initargs)
  3960.     (apply #'make-instance (find-class class) initargs)
  3961.   )
  3962. )
  3963. #|
  3964. (defmethod make-instance ((class standard-class) &rest initargs &key &allow-other-keys)
  3965.   ; 28.1.9.3., 28.1.9.4. default-initargs zur Kenntnis nehmen:
  3966.   (dolist (default-initarg (class-default-initargs class))
  3967.     (let ((nothing default-initarg))
  3968.       (when (eq (getf initargs (car default-initarg) nothing) nothing)
  3969.         (setq initargs
  3970.               (append initargs
  3971.                 (list (car default-initarg)
  3972.                       (let ((init (cdr default-initarg)))
  3973.                         (if (car init) (funcall (car init)) (cdr init))
  3974.   ) ) ) )     ) )     )
  3975.   #|
  3976.   ; 28.1.9.2. validity of initialization arguments
  3977.   (sys::keyword-test initargs
  3978.                      (union (class-valid-initargs class)
  3979.                             (applicable-keywords #'initialize-instance class) ; ??
  3980.   )                  )
  3981.   (let ((instance (allocate-instance class)))
  3982.     (apply #'initialize-instance instance initargs)
  3983.   )
  3984.   |#
  3985.   (let ((h (gethash class *make-instance-table*)))
  3986.     (if h
  3987.       (progn
  3988.         ; 28.1.9.2. validity of initialization arguments
  3989.         (let ((valid-keywords (car h)))
  3990.           (sys::keyword-test initargs valid-keywords)
  3991.         )
  3992.         (let ((instance (allocate-instance class)))
  3993.           (if (not (eq (cadr h) #'clos::%initialize-instance))
  3994.             ; effektive Methode von initialize-instance anwenden:
  3995.             (apply (cadr h) instance initargs)
  3996.             ; clos::%initialize-instance lΣ▀t sich vereinfachen (man braucht
  3997.             ; nicht nochmal in *make-instance-table* nachzusehen):
  3998.             (if (not (eq (cddr h) #'clos::%shared-initialize))
  3999.               ; effektive Methode von shared-initialize anwenden:
  4000.               (apply (cddr h) instance 'T initargs)
  4001.               ...
  4002.             )
  4003.       ) ) )
  4004.       (apply #'initial-make-instance class initargs)
  4005. ) ) )
  4006. |#
  4007. ; die Haupt-Arbeit erledigt ein SUBR:
  4008. (do-defmethod 'make-instance
  4009.   (make-standard-method
  4010.     :initfunction #'(lambda (gf) (declare (ignore gf))
  4011.                       (cons #'clos::%make-instance '(T))
  4012.                     )
  4013.     :wants-next-method-p nil
  4014.     :parameter-specializers (list (find-class 'standard-class))
  4015.     :qualifiers '()
  4016.     :signature '(1 0 t t () t)
  4017. ) )
  4018. (do-defmethod 'make-instance
  4019.   (make-standard-method
  4020.     :initfunction #'(lambda (gf) (declare (ignore gf))
  4021.                       (cons #'clos::%make-instance '(T))
  4022.                     )
  4023.     :wants-next-method-p nil
  4024.     :parameter-specializers (list (find-class 'structure-class))
  4025.     :qualifiers '()
  4026.     :signature '(1 0 t t () t)
  4027. ) )
  4028. (defun initial-make-instance (class &rest initargs)
  4029.   (let ((valid-keywords (valid-make-instance-keywords class)))
  4030.     ; 28.1.9.2. validity of initialization arguments
  4031.     (sys::keyword-test initargs valid-keywords)
  4032.     (let ((instance (%allocate-instance class)))
  4033.       (let ((efs (make-instance-table-entry2 instance)))
  4034.         (setf (gethash class *make-instance-table*) (cons valid-keywords efs))
  4035.         ; effektive Methode von INITIALIZE-INSTANCE anwenden:
  4036.         (apply (car efs) instance initargs)
  4037. ) ) ) )
  4038.  
  4039.  
  4040. ;; Users want to be able to create instances of subclasses of <standard-class>
  4041. ;; and <structure-class>. So, when creating a class, we now go through
  4042. ;; MAKE-INSTANCE and INITIALIZE-INSTANCE.
  4043. (defun make-instance-standard-class (&rest args)
  4044.   (apply #'make-instance args)
  4045. )
  4046. (defun make-instance-structure-class (&rest args)
  4047.   (apply #'make-instance args)
  4048. )
  4049. (defmethod initialize-instance ((new-class-object standard-class) &rest args
  4050.                   &key name (metaclass <standard-class>)
  4051.                        direct-superclasses direct-slots
  4052.                        direct-default-initargs
  4053.                                )
  4054.   (declare (ignore direct-superclasses direct-slots direct-default-initargs))
  4055.   (setf (class-classname new-class-object) name)
  4056.   (setf (class-metaclass new-class-object) metaclass) ; = (class-of new-class-object)
  4057.   (apply #'initialize-instance-standard-class new-class-object args)
  4058.   (call-next-method)
  4059.   new-class-object
  4060. )
  4061. (defmethod initialize-instance ((new-class-object structure-class) &rest args
  4062.                   &key name (metaclass <structure-class>) direct-superclasses
  4063.                        direct-slots direct-default-initargs
  4064.                        names slots size
  4065.                                )
  4066.   (declare (ignore direct-superclasses direct-slots direct-default-initargs names slots size))
  4067.   (setf (class-classname new-class-object) name)
  4068.   (setf (class-metaclass new-class-object) metaclass) ; = (class-of new-class-object)
  4069.   (apply #'initialize-instance-structure-class new-class-object args)
  4070.   (call-next-method)
  4071.   (when (subclassp new-class-object <class>)
  4072.     (setf (get (class-classname new-class-object) 'sys::structure-print) #'print-class)
  4073.   )
  4074.   new-class-object
  4075. )
  4076.  
  4077.